diff --git a/CInterface/Battling/Battle.cpp b/CInterface/Battling/Battle.cpp index 26cca7a..a594366 100644 --- a/CInterface/Battling/Battle.cpp +++ b/CInterface/Battling/Battle.cpp @@ -1,39 +1,45 @@ #include "../../src/Battling/Models/Battle.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; -export Battle* CreatureLib_Battle_Construct(const BattleLibrary* library, BattleParty* partyArr[], +export uint8_t CreatureLib_Battle_Construct(Battle*& out, const BattleLibrary* library, BattleParty* partyArr[], size_t numberOfParties, bool canFlee, uint8_t numberOfSides, uint8_t creaturesPerSide) { - List parties(partyArr, partyArr + numberOfParties); - return new Battle(library, parties, canFlee, numberOfSides, creaturesPerSide); + Try(List parties(partyArr, partyArr + numberOfParties); + out = new Battle(library, parties, canFlee, numberOfSides, creaturesPerSide);) } export void CreatureLib_Battle_Destruct(const Battle* p) { delete p; } export const BattleLibrary* CreatureLib_Battle_GetLibrary(const Battle* p) { return p->GetLibrary(); } -export bool CreatureLib_Battle_CanUse(Battle* p, const BaseTurnChoice* turnChoice) { return p->CanUse(turnChoice); } -export bool CreatureLib_Battle_TrySetChoice(Battle* p, BaseTurnChoice* turnChoice) { - return p->TrySetChoice(turnChoice); +export uint8_t CreatureLib_Battle_CanUse(bool& out, Battle* p, const BaseTurnChoice* turnChoice) { + Try(out = p->CanUse(turnChoice);) +} +export uint8_t CreatureLib_Battle_TrySetChoice(bool& out, Battle* p, BaseTurnChoice* turnChoice) { + Try(out = p->TrySetChoice(turnChoice);) } export bool CreatureLib_Battle_CanFlee(const Battle* p) { return p->CanFlee(); } -export void CreatureLib_Battle_CheckChoicesSetAndRun(Battle* p) { p->CheckChoicesSetAndRun(); } +export uint8_t CreatureLib_Battle_CheckChoicesSetAndRun(Battle* p) { Try(p->CheckChoicesSetAndRun();) } export ChoiceQueue* CreatureLib_Battle_GetCurrentTurnQueue(const Battle* p) { return p->GetCurrentTurnQueue(); } export BattleRandom* CreatureLib_Battle_GetRandom(Battle* p) { return p->GetRandom(); } -export bool CreatureLib_Battle_CreatureInField(const Battle* p, Creature* c) { return p->CreatureInField(c); } -export Creature* CreatureLib_Battle_GetCreature(const Battle* p, uint8_t side, uint8_t target) { - return p->GetCreature(side, target); +export uint8_t CreatureLib_Battle_CreatureInField(bool& out, const Battle* p, Creature* c) { + Try(out = p->CreatureInField(c);) +} +export uint8_t CreatureLib_Battle_GetCreature(Creature*& out, const Battle* p, uint8_t side, uint8_t target) { + Try(out = p->GetCreature(side, target);) } -export void CreatureLib_Battle_ForceRecall(Battle* p, uint8_t side, uint8_t target) { p->ForceRecall(side, target); } -export void CreatureLib_Battle_SwitchCreature(Battle* p, uint8_t side, uint8_t target, Creature* c) { - p->SwitchCreature(side, target, c); +export uint8_t CreatureLib_Battle_ForceRecall(Battle* p, uint8_t side, uint8_t target) { + Try(p->ForceRecall(side, target);) } -export bool CreatureLib_Battle_CanSlotBeFilled(const Battle* p, uint8_t side, uint8_t target) { - return p->CanSlotBeFilled(side, target); +export uint8_t CreatureLib_Battle_SwitchCreature(Battle* p, uint8_t side, uint8_t target, Creature* c) { + Try(p->SwitchCreature(side, target, c);) } -export void CreatureLib_Battle_ValidateBattleState(Battle* p) { p->ValidateBattleState(); } +export uint8_t CreatureLib_Battle_CanSlotBeFilled(bool& out, const Battle* p, uint8_t side, uint8_t target) { + Try(out = p->CanSlotBeFilled(side, target);) +} +export uint8_t CreatureLib_Battle_ValidateBattleState(Battle* p) { Try(p->ValidateBattleState();) } export bool CreatureLib_Battle_HasEnded(const Battle* p) { return p->HasEnded(); } export bool CreatureLib_Battle_HasConclusiveResult(const Battle* p) { return p->GetResult().IsConclusiveResult(); } @@ -45,22 +51,24 @@ export BattleSide* const* CreatureLib_Battle_GetSides(const Battle* p) { return export Script* CreatureLib_Battle_GetVolatileScript(Battle* p, const char* key) { return p->GetVolatileScript(ConstString::GetHash(key)); } -export void CreatureLib_Battle_AddVolatileScriptByName(Battle* p, const char* key) { - p->AddVolatileScript(ConstString(key)); +export uint8_t CreatureLib_Battle_AddVolatileScriptByName(Battle* p, const char* key) { + Try(p->AddVolatileScript(ConstString(key));) } -export void CreatureLib_Battle_AddVolatileScript(Battle* p, Script* script) { p->AddVolatileScript(script); } +export uint8_t CreatureLib_Battle_AddVolatileScript(Battle* p, Script* script) { Try(p->AddVolatileScript(script);) } -export void CreatureLib_Battle_RemoveVolatileScript(Battle* p, const char* key) { - p->RemoveVolatileScript(ConstString::GetHash(key)); +export uint8_t CreatureLib_Battle_RemoveVolatileScript(Battle* p, const char* key) { + Try(p->RemoveVolatileScript(ConstString::GetHash(key));) } -export void CreatureLib_Battle_RemoveVolatileScriptWithScript(Battle* p, Script* script) { - p->RemoveVolatileScript(script); +export uint8_t CreatureLib_Battle_RemoveVolatileScriptWithScript(Battle* p, Script* script) { + Try(p->RemoveVolatileScript(script);) } export bool CreatureLib_Battle_HasVolatileScript(Battle* p, const char* key) { return p->HasVolatileScript(ConstString::GetHash(key)); } -export void CreatureLib_Battle_RegisterEventListener(Battle* p, void (*func)(const EventData*)) { - p->RegisterEventListener(func); +export uint8_t CreatureLib_Battle_RegisterEventListener(Battle* p, void (*func)(const EventData*)) { + Try(p->RegisterEventListener(func);) +} +export uint8_t CreatureLib_Battle_TriggerEventListener(Battle* p, EventData* data) { + Try(p->TriggerEventListener(data);) } -export void CreatureLib_Battle_TriggerEventListener(Battle* p, EventData* data) { p->TriggerEventListener(data); } diff --git a/CInterface/Battling/BattleLibrary.cpp b/CInterface/Battling/BattleLibrary.cpp index d4ce98e..3967b3a 100644 --- a/CInterface/Battling/BattleLibrary.cpp +++ b/CInterface/Battling/BattleLibrary.cpp @@ -1,5 +1,5 @@ #include "../../src/Battling/Library/BattleLibrary.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export const BattleLibrary* CreatureLib_BattleLibrary_Construct(const CreatureLib::Library::DataLibrary* staticLib, diff --git a/CInterface/Battling/BattleParty.cpp b/CInterface/Battling/BattleParty.cpp index f4d8f14..6cd72bc 100644 --- a/CInterface/Battling/BattleParty.cpp +++ b/CInterface/Battling/BattleParty.cpp @@ -1,22 +1,22 @@ #include "../../src/Battling/Models/BattleParty.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; // Note that creatureIndices should be twice the size of numberOfIndices, and have index of side, index of creature on // side, one after the other. -export BattleParty* CreatureLib_BattleParty_Construct(CreatureParty* p, uint8_t creatureIndices[], - size_t numberOfIndices) { - Arbutils::Collections::List indices(numberOfIndices); - for (size_t i = 0; i < numberOfIndices; i++) { - indices[i] = CreatureIndex(creatureIndices[i * 2], creatureIndices[i * 2 + 1]); - } - return new BattleParty(p, indices); +export uint8_t CreatureLib_BattleParty_Construct(BattleParty*& out, CreatureParty* p, uint8_t creatureIndices[], + size_t numberOfIndices) { + Try(Arbutils::Collections::List indices(numberOfIndices); + for (size_t i = 0; i < numberOfIndices; i++) { + indices[i] = CreatureIndex(creatureIndices[i * 2], creatureIndices[i * 2 + 1]); + } out = new BattleParty(p, indices);) } export void CreatureLib_BattleParty_Destruct(const BattleParty* p) { delete p; } -export bool CreatureLib_BattleParty_IsResponsibleForIndex(const BattleParty* p, uint8_t side, uint8_t creature) { - return p->IsResponsibleForIndex(side, creature); +export uint8_t CreatureLib_BattleParty_IsResponsibleForIndex(bool& out, const BattleParty* p, uint8_t side, + uint8_t creature) { + Try(out = p->IsResponsibleForIndex(side, creature);) } export bool CreatureLib_BattleParty_HasCreaturesNotInField(const BattleParty* p) { return p->HasCreaturesNotInField(); } diff --git a/CInterface/Battling/BattleStatCalculator.cpp b/CInterface/Battling/BattleStatCalculator.cpp index de3f989..4e6724d 100644 --- a/CInterface/Battling/BattleStatCalculator.cpp +++ b/CInterface/Battling/BattleStatCalculator.cpp @@ -1,16 +1,18 @@ #include "../../src/Battling/Library/BattleStatCalculator.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export const BattleStatCalculator* CreatureLib_BattleStatCalculator_Construct() { return new BattleStatCalculator(); } export void CreatureLib_BattleStatCalculator_Destruct(const BattleStatCalculator* p) { delete p; } -export uint32_t CreatureLib_BattleStatCalculator_CalculateFlatStat(const BattleStatCalculator* p, Creature* creature, - CreatureLib::Library::Statistic stat) { - return p->CalculateFlatStat(creature, stat); +export uint8_t CreatureLib_BattleStatCalculator_CalculateFlatStat(uint32_t& out, const BattleStatCalculator* p, + Creature* creature, + CreatureLib::Library::Statistic stat) { + Try(out = p->CalculateFlatStat(creature, stat);) } -export uint32_t CreatureLib_BattleStatCalculator_CalculateBoostedStat(const BattleStatCalculator* p, Creature* creature, - CreatureLib::Library::Statistic stat) { - return p->CalculateBoostedStat(creature, stat); +export uint8_t CreatureLib_BattleStatCalculator_CalculateBoostedStat(uint32_t& out, const BattleStatCalculator* p, + Creature* creature, + CreatureLib::Library::Statistic stat) { + Try(out = p->CalculateBoostedStat(creature, stat);) } \ No newline at end of file diff --git a/CInterface/Battling/Creature.cpp b/CInterface/Battling/Creature.cpp index 2c51bc9..6ebee8f 100644 --- a/CInterface/Battling/Creature.cpp +++ b/CInterface/Battling/Creature.cpp @@ -1,18 +1,18 @@ #include "../../src/Battling/Models/Creature.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; using ConstString = Arbutils::CaseInsensitiveConstString; -export Creature* CreatureLib_Creature_Construct(const BattleLibrary* library, - const CreatureLib::Library::CreatureSpecies* species, - const CreatureLib::Library::SpeciesVariant* variant, uint8_t level, - uint32_t experience, uint32_t uid, CreatureLib::Library::Gender gender, - uint8_t coloring, const CreatureLib::Library::Item* heldItem, - std::string nickname, bool secretTalent, const uint8_t talent, - LearnedAttack* attacks[], size_t attacksNum) { - auto attacksVec = List(attacks, attacks + attacksNum); - return new Creature(library, species, variant, level, experience, uid, gender, coloring, heldItem, nickname, - CreatureLib::Library::TalentIndex(secretTalent, talent), attacksVec); +export uint8_t CreatureLib_Creature_Construct(Creature*& out, const BattleLibrary* library, + const CreatureLib::Library::CreatureSpecies* species, + const CreatureLib::Library::SpeciesVariant* variant, uint8_t level, + uint32_t experience, uint32_t uid, CreatureLib::Library::Gender gender, + uint8_t coloring, const CreatureLib::Library::Item* heldItem, + std::string nickname, bool secretTalent, const uint8_t talent, + LearnedAttack* attacks[], size_t attacksNum) { + Try(auto attacksVec = List(attacks, attacks + attacksNum); + out = new Creature(library, species, variant, level, experience, uid, gender, coloring, heldItem, nickname, + CreatureLib::Library::TalentIndex(secretTalent, talent), attacksVec);) }; export void CreatureLib_Creature_Destruct(const Creature* p) { delete p; } @@ -32,10 +32,10 @@ export bool CreatureLib_Creature_HasHeldItem(const Creature* p, const char* name } export bool CreatureLib_Creature_HasHeldItemWithHash(const Creature* p, uint32_t hash) { return p->HasHeldItem(hash); } SIMPLE_GET_FUNC(Creature, GetHeldItem, const CreatureLib::Library::Item*); -export void CreatureLib_Creature_SetHeldItem(Creature* p, const char* name) { - return p->SetHeldItem(ConstString(name)); +export uint8_t CreatureLib_Creature_SetHeldItem(Creature* p, const char* name) { + Try(p->SetHeldItem(ConstString(name));) } -export void CreatureLib_Creature_SetHeldItemWithHash(Creature* p, uint32_t hash) { return p->SetHeldItem(hash); } +export uint8_t CreatureLib_Creature_SetHeldItemWithHash(Creature* p, uint32_t hash) { Try(p->SetHeldItem(hash);) } export void CreatureLib_Creature_SetHeldItemFromItem(Creature* p, const CreatureLib::Library::Item* item) { return p->SetHeldItem(item); } @@ -48,28 +48,31 @@ export size_t CreatureLib_Creature_GetTypesCount(Creature* p) { return p->GetTyp export const uint8_t* CreatureLib_Creature_GetTypes(Creature* p) { return p->GetTypes().RawData(); } export bool CreatureLib_Creature_HasType(Creature* p, uint8_t type) { return p->HasType(type); } SIMPLE_GET_FUNC(Creature, GetMaxHealth, uint32_t); -export void CreatureLib_Creature_ChangeLevelBy(Creature* p, int8_t level) { return p->ChangeLevelBy(level); } -export void CreatureLib_Creature_Damage(Creature* p, uint32_t damage, DamageSource source) { - p->Damage(damage, source); +export uint8_t CreatureLib_Creature_ChangeLevelBy(Creature* p, int8_t level) { Try(p->ChangeLevelBy(level);) } +export uint8_t CreatureLib_Creature_Damage(Creature* p, uint32_t damage, DamageSource source) { + Try(p->Damage(damage, source);) } -export void CreatureLib_Creature_Heal(Creature* p, uint32_t health, bool canRevive) { p->Heal(health, canRevive); } -export void CreatureLib_Creature_OverrideActiveTalent(Creature* p, const char* talent) { - p->OverrideActiveTalent(ConstString(talent)); +export uint8_t CreatureLib_Creature_Heal(Creature* p, uint32_t health, bool canRevive) { + Try(p->Heal(health, canRevive);) } -export void CreatureLib_Creature_AddExperience(Creature* p, uint32_t experience) { - return p->AddExperience(experience); +export uint8_t CreatureLib_Creature_OverrideActiveTalent(Creature* p, const char* talent) { + Try(p->OverrideActiveTalent(ConstString(talent));) } -export void CreatureLib_Creature_ClearVolatileScripts(Creature* p) { return p->ClearVolatileScripts(); } -export void CreatureLib_Creature_AddVolatileScriptByName(Creature* p, const char* scriptName) { - return p->AddVolatileScript(ConstString(scriptName)); +export uint8_t CreatureLib_Creature_AddExperience(Creature* p, uint32_t experience) { + Try(p->AddExperience(experience);) } -export void CreatureLib_Creature_AddVolatileScript(Creature* p, Script* script) { - return p->AddVolatileScript(script); } -export void CreatureLib_Creature_RemoveVolatileScriptByName(Creature* p, const char* scriptName) { - return p->RemoveVolatileScript(ConstString(scriptName)); +export uint8_t CreatureLib_Creature_ClearVolatileScripts(Creature* p) { Try(p->ClearVolatileScripts();) } +export uint8_t CreatureLib_Creature_AddVolatileScriptByName(Creature* p, const char* scriptName) { + Try(p->AddVolatileScript(ConstString(scriptName));) } -export void CreatureLib_Creature_RemoveVolatileScript(Creature* p, Script* script) { - return p->RemoveVolatileScript(script); +export uint8_t CreatureLib_Creature_AddVolatileScript(Creature* p, Script* script) { + Try(p->AddVolatileScript(script);) +} +export uint8_t CreatureLib_Creature_RemoveVolatileScriptByName(Creature* p, const char* scriptName) { + Try(p->RemoveVolatileScript(ConstString(scriptName));) +} +export uint8_t CreatureLib_Creature_RemoveVolatileScript(Creature* p, Script* script) { + Try(p->RemoveVolatileScript(script);) } export bool CreatureLib_Creature_HasVolatileScript(Creature* p, const char* scriptName) { return p->HasVolatileScript(ConstString(scriptName)); diff --git a/CInterface/Battling/CreatureParty.cpp b/CInterface/Battling/CreatureParty.cpp index a3d3b6f..de615b2 100644 --- a/CInterface/Battling/CreatureParty.cpp +++ b/CInterface/Battling/CreatureParty.cpp @@ -1,5 +1,5 @@ #include "../../src/Battling/Models/CreatureParty.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export CreatureParty* CreatureLib_CreatureParty_ConstructWithSize(size_t size) { return new CreatureParty(size); } @@ -9,11 +9,11 @@ export CreatureParty* CreatureLib_CreatureParty_ConstructFromArray(Creature* cre export void CreatureLib_CreatureParty_Destruct(const CreatureParty* p) { delete p; } -export Creature* CreatureLib_CreatureParty_GetAtIndex(const CreatureParty* p, size_t index) { - return p->GetAtIndex(index); +export uint8_t CreatureLib_CreatureParty_GetAtIndex(Creature*& out, const CreatureParty* p, size_t index) { + Try(out = p->GetAtIndex(index);) } -export void CreatureLib_CreatureParty_Switch(CreatureParty* p, size_t a, size_t b) { p->Switch(a, b); } +export uint8_t CreatureLib_CreatureParty_Switch(CreatureParty* p, size_t a, size_t b) { Try(p->Switch(a, b);) } export bool CreatureLib_CreatureParty_HasAvailableCreatures(const CreatureParty* p) { return p->HasAvailableCreatures(); diff --git a/CInterface/Battling/DamageLibrary.cpp b/CInterface/Battling/DamageLibrary.cpp index 9766e7c..4f78380 100644 --- a/CInterface/Battling/DamageLibrary.cpp +++ b/CInterface/Battling/DamageLibrary.cpp @@ -1,25 +1,25 @@ #include "../../src/Battling/Library/DamageLibrary.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export const DamageLibrary* CreatureLib_DamageLibrary_Construct() { return new DamageLibrary(); } export void CreatureLib_DamageLibrary_Destruct(const DamageLibrary* p) { delete p; } -export uint32_t CreatureLib_DamageLibrary_GetDamage(const DamageLibrary* p, ExecutingAttack* attack, Creature* target, - uint8_t hitIndex) { - return p->GetDamage(attack, target, hitIndex); +export uint8_t CreatureLib_DamageLibrary_GetDamage(uint32_t& out, const DamageLibrary* p, ExecutingAttack* attack, + Creature* target, uint8_t hitIndex) { + Try(out = p->GetDamage(attack, target, hitIndex);) } -export uint8_t CreatureLib_DamageLibrary_GetBasePower(const DamageLibrary* p, ExecutingAttack* attack, Creature* target, - uint8_t hitIndex) { - return p->GetBasePower(attack, target, hitIndex); +export uint8_t CreatureLib_DamageLibrary_GetBasePower(uint8_t& out, const DamageLibrary* p, ExecutingAttack* attack, + Creature* target, uint8_t hitIndex) { + Try(out = p->GetBasePower(attack, target, hitIndex);) } -export float CreatureLib_DamageLibrary_GetStatModifier(const DamageLibrary* p, ExecutingAttack* attack, +export float CreatureLib_DamageLibrary_GetStatModifier(float& out, const DamageLibrary* p, ExecutingAttack* attack, Creature* target, uint8_t hitIndex) { - return p->GetStatModifier(attack, target, hitIndex); + Try(out = p->GetStatModifier(attack, target, hitIndex);) } -export float CreatureLib_DamageLibrary_GetDamageModifier(const DamageLibrary* p, ExecutingAttack* attack, +export float CreatureLib_DamageLibrary_GetDamageModifier(float& out, const DamageLibrary* p, ExecutingAttack* attack, Creature* target, uint8_t hitIndex) { - return p->GetDamageModifier(attack, target, hitIndex); + Try(out = p->GetDamageModifier(attack, target, hitIndex);) } diff --git a/CInterface/Battling/EventData.cpp b/CInterface/Battling/EventData.cpp index 7074dd2..4c664ef 100644 --- a/CInterface/Battling/EventData.cpp +++ b/CInterface/Battling/EventData.cpp @@ -1,5 +1,5 @@ #include "../../src/Battling/EventHooks/EventData.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export void CreatureLib_EventData_Destruct(const EventData* p) { delete p; } diff --git a/CInterface/Battling/ExperienceLibrary.cpp b/CInterface/Battling/ExperienceLibrary.cpp index 7f07c27..2f5e912 100644 --- a/CInterface/Battling/ExperienceLibrary.cpp +++ b/CInterface/Battling/ExperienceLibrary.cpp @@ -1,13 +1,13 @@ #include "../../src/Battling/Library/ExperienceLibrary.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export const ExperienceLibrary* CreatureLib_ExperienceLibrary_Construct() { return new ExperienceLibrary(); } export void CreatureLib_ExperienceLibrary_Destruct(const ExperienceLibrary* p) { delete p; } -export void CreatureLib_ExperienceLibrary_HandleExperienceGain(const ExperienceLibrary* p, Creature* faintedMon, - Creature* opponents[], size_t opponentsCount) { - auto set = std::unordered_set(opponents, opponents + opponentsCount); - p->HandleExperienceGain(faintedMon, set); +export uint8_t CreatureLib_ExperienceLibrary_HandleExperienceGain(const ExperienceLibrary* p, Creature* faintedMon, + Creature* opponents[], size_t opponentsCount) { + Try(auto set = std::unordered_set(opponents, opponents + opponentsCount); + p->HandleExperienceGain(faintedMon, set);) } diff --git a/CInterface/Battling/MiscLibrary.cpp b/CInterface/Battling/MiscLibrary.cpp index b0e21f0..8b4c7f7 100644 --- a/CInterface/Battling/MiscLibrary.cpp +++ b/CInterface/Battling/MiscLibrary.cpp @@ -1,18 +1,19 @@ #include "../../src/Battling/Library/MiscLibrary.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export MiscLibrary* CreatureLib_MiscLibrary_Construct() { return new MiscLibrary(); } export void CreatureLib_MiscLibrary_Destruct(const MiscLibrary* p) { delete p; } -export bool CreatureLib_MiscLibrary_IsCritical(MiscLibrary* p, ExecutingAttack* attack, Creature* target, uint8_t hit) { - return p->IsCritical(attack, target, hit); +export uint8_t CreatureLib_MiscLibrary_IsCritical(bool& out, MiscLibrary* p, ExecutingAttack* attack, Creature* target, + uint8_t hit) { + Try(out = p->IsCritical(attack, target, hit);) }; -export bool CreatureLib_MiscLibrary_CanFlee(MiscLibrary* p, FleeTurnChoice* switchChoice) { - return p->CanFlee(switchChoice); +export uint8_t CreatureLib_MiscLibrary_CanFlee(bool& out, MiscLibrary* p, FleeTurnChoice* switchChoice) { + Try(out = p->CanFlee(switchChoice);) }; -export BaseTurnChoice* CreatureLib_MiscLibrary_ReplacementAttack(MiscLibrary* p, Creature* user, uint8_t sideTarget, - uint8_t creatureTarget) { - return p->ReplacementAttack(user, CreatureIndex(sideTarget, creatureTarget)); +export uint8_t CreatureLib_MiscLibrary_ReplacementAttack(BaseTurnChoice*& out, MiscLibrary* p, Creature* user, + uint8_t sideTarget, uint8_t creatureTarget) { + Try(out = p->ReplacementAttack(user, CreatureIndex(sideTarget, creatureTarget));) }; diff --git a/CInterface/Battling/ScriptResolver.cpp b/CInterface/Battling/ScriptResolver.cpp index 606ecab..9a77ad6 100644 --- a/CInterface/Battling/ScriptResolver.cpp +++ b/CInterface/Battling/ScriptResolver.cpp @@ -1,15 +1,15 @@ #include "../../src/Battling/ScriptHandling/ScriptResolver.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export ScriptResolver* CreatureLib_ScriptResolver_Construct() { return new ScriptResolver(); } export void CreatureLib_ScriptResolver_Destruct(const ScriptResolver* p) { delete p; } -export void CreatureLib_ScriptResolver_Initialize(ScriptResolver* p, BattleLibrary* library) { - p->Initialize(library); +export uint8_t CreatureLib_ScriptResolver_Initialize(ScriptResolver* p, BattleLibrary* library) { + Try(p->Initialize(library);) }; -export Script* CreatureLib_ScriptResolver_LoadScript(ScriptResolver* p, ScriptCategory category, +export uint8_t CreatureLib_ScriptResolver_LoadScript(Script*& out, ScriptResolver* p, ScriptCategory category, const char* scriptName) { - return p->LoadScript(category, ConstString(scriptName)); + Try(out = p->LoadScript(category, ConstString(scriptName));) }; diff --git a/CInterface/Battling/TurnChoices.cpp b/CInterface/Battling/TurnChoices.cpp index 02e5431..3b875e4 100644 --- a/CInterface/Battling/TurnChoices.cpp +++ b/CInterface/Battling/TurnChoices.cpp @@ -2,7 +2,7 @@ #include "../../src/Battling/TurnChoices/FleeTurnChoice.hpp" #include "../../src/Battling/TurnChoices/PassTurnChoice.hpp" #include "../../src/Battling/TurnChoices/SwitchTurnChoice.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Battling; export AttackTurnChoice* CreatureLib_AttackTurnChoice_Construct(Creature* user, LearnedAttack* attack, @@ -25,7 +25,9 @@ SIMPLE_GET_FUNC(BaseTurnChoice, GetUser, Creature*) SIMPLE_GET_FUNC(AttackTurnChoice, GetAttack, LearnedAttack*) SIMPLE_GET_FUNC(AttackTurnChoice, GetKind, TurnChoiceKind) -SIMPLE_GET_FUNC(AttackTurnChoice, GetPriority, int8_t) + +export uint8_t CreatureLib_BaseTurnChoice_GetPriority(int8_t& out, AttackTurnChoice* p) { Try(out = p->GetPriority()); } + SIMPLE_GET_FUNC(AttackTurnChoice, GetAttackScript, Script*) export uint8_t CreatureLib_BaseTurnChoice_GetTargetSideIndex(const AttackTurnChoice* p) { return p->GetTarget().GetSideIndex(); diff --git a/CInterface/Core.cpp b/CInterface/Core.cpp new file mode 100644 index 0000000..c097023 --- /dev/null +++ b/CInterface/Core.cpp @@ -0,0 +1,4 @@ +#include "Core.hpp" + +std::string ExceptionHandler::_lastException = ""; +export const char* GetLastException() { return ExceptionHandler::GetLastException(); } diff --git a/CInterface/Core.hpp b/CInterface/Core.hpp new file mode 100644 index 0000000..966e3ed --- /dev/null +++ b/CInterface/Core.hpp @@ -0,0 +1,26 @@ +#ifndef CREATURELIB_CORE_HPP +#define CREATURELIB_CORE_HPP + +#include +#include +#include +#define export extern "C" + +class ExceptionHandler { + static std::string _lastException; + +public: + static void SetLastException(const std::exception& e) { _lastException = std::string(e.what()); } + static const char* GetLastException() { return _lastException.c_str(); } +}; + +#define Try(data) \ + try { \ + data; \ + return 0; \ + } catch (const std::exception& e) { \ + ExceptionHandler::SetLastException(e); \ + return 1; \ + } + +#endif // CREATURELIB_CORE_HPP diff --git a/CInterface/Library/AttackData.cpp b/CInterface/Library/AttackData.cpp index 2f160b8..e1d71ae 100644 --- a/CInterface/Library/AttackData.cpp +++ b/CInterface/Library/AttackData.cpp @@ -1,18 +1,16 @@ #include "../../src/Library/Attacks/AttackData.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; -export AttackData* CreatureLib_AttackData_Construct(const char* name, uint8_t type, AttackCategory category, - uint8_t power, uint8_t accuracy, uint8_t baseUsage, - AttackTarget target, int8_t priority, const char* flags[], - size_t flagsCount) { - std::unordered_set conversedFlags(flagsCount); - for (size_t i = 0; i < flagsCount; i++) { - conversedFlags.insert(ConstString::GetHash(flags[i])); - } +export uint8_t CreatureLib_AttackData_Construct(AttackData*& out, const char* name, uint8_t type, + AttackCategory category, uint8_t power, uint8_t accuracy, + uint8_t baseUsage, AttackTarget target, int8_t priority, + const char* flags[], size_t flagsCount) { + Try(std::unordered_set conversedFlags(flagsCount); + for (size_t i = 0; i < flagsCount; i++) { conversedFlags.insert(ConstString::GetHash(flags[i])); } - return new AttackData(ConstString(name), type, category, power, accuracy, baseUsage, target, priority, - conversedFlags); + out = new AttackData(ConstString(name), type, category, power, accuracy, baseUsage, target, priority, + conversedFlags);) }; export void CreatureLib_AttackData_Destruct(const AttackData* p) { delete p; } diff --git a/CInterface/Library/AttackLibrary.cpp b/CInterface/Library/AttackLibrary.cpp index 773171c..a886c4f 100644 --- a/CInterface/Library/AttackLibrary.cpp +++ b/CInterface/Library/AttackLibrary.cpp @@ -1,10 +1,9 @@ #include "../../src/Library/AttackLibrary.hpp" #include "BaseLibrary.cpp" -#define export extern "C" using namespace CreatureLib::Library; -export const AttackLibrary* CreatureLib_AttackLibrary_Construct(size_t initialCapacity = 32) { - return new AttackLibrary(initialCapacity); +export uint8_t CreatureLib_AttackLibrary_Construct(AttackLibrary*& library, size_t initialCapacity = 32) { + Try(library = new AttackLibrary(initialCapacity);) }; export void CreatureLib_AttackLibrary_Destruct(const AttackLibrary* p) { delete p; } diff --git a/CInterface/Library/BaseLibrary.cpp b/CInterface/Library/BaseLibrary.cpp index 0d9130b..63ee1ae 100644 --- a/CInterface/Library/BaseLibrary.cpp +++ b/CInterface/Library/BaseLibrary.cpp @@ -1,32 +1,34 @@ -#define export extern "C" +#include "../Core.hpp" #define BASELIBRARY(simpleName, fullname, returnType) \ - export void simpleName##_Insert(fullname* p, const char* name, returnType* t) { \ - p->Insert(Arbutils::CaseInsensitiveConstString::GetHash(name), t); \ + export uint8_t simpleName##_Insert(fullname* p, const char* name, returnType* t) { \ + Try(p->Insert(Arbutils::CaseInsensitiveConstString::GetHash(name), t);) \ } \ \ - export void simpleName##_InsertWithHash(fullname* p, uint32_t hashedKey, returnType* t) { \ - p->Insert(hashedKey, t); \ + export uint8_t simpleName##_InsertWithHash(fullname* p, uint32_t hashedKey, returnType* t) { \ + Try(p->Insert(hashedKey, t);) \ } \ \ - export void simpleName##_Delete(fullname* p, const char* name) { \ - p->Delete(Arbutils::CaseInsensitiveConstString::GetHash(name)); \ + export uint8_t simpleName##_Delete(fullname* p, const char* name) { \ + Try(p->Delete(Arbutils::CaseInsensitiveConstString::GetHash(name));) \ } \ \ - export void simpleName##_DeleteWithHash(fullname* p, uint32_t hashedKey) { p->Delete(hashedKey); } \ + export uint8_t simpleName##_DeleteWithHash(fullname* p, uint32_t hashedKey) { Try(p->Delete(hashedKey);) } \ \ - export bool simpleName##_TryGet(fullname* p, const char* name, const returnType* out) { \ + export bool simpleName##_TryGet(fullname* p, const char* name, const returnType*& out) { \ return p->TryGet(Arbutils::CaseInsensitiveConstString::GetHash(name), out); \ } \ \ - export bool simpleName##_TryGetWithHash(fullname* p, uint32_t hashedKey, const returnType* out) { \ + export bool simpleName##_TryGetWithHash(fullname* p, uint32_t hashedKey, const returnType*& out) { \ return p->TryGet(hashedKey, out); \ } \ \ - export bool simpleName##_Get(fullname* p, const char* name) { \ - return p->Get(Arbutils::CaseInsensitiveConstString::GetHash(name)); \ + export uint8_t simpleName##_Get(fullname* p, const char* name, const returnType*& out) { \ + Try(out = p->Get(Arbutils::CaseInsensitiveConstString::GetHash(name));) \ } \ \ - export bool simpleName##_GetWithHash(fullname* p, uint32_t hashedKey) { return p->Get(hashedKey); } \ + export uint8_t simpleName##_GetWithHash(fullname* p, uint32_t hashedKey, const returnType*& out) { \ + Try(out = p->Get(hashedKey);) \ + } \ \ export size_t simpleName##_GetCount(fullname* p) { return p->GetCount(); } diff --git a/CInterface/Library/CreatureSpecies.cpp b/CInterface/Library/CreatureSpecies.cpp index cf3c632..8419ce6 100644 --- a/CInterface/Library/CreatureSpecies.cpp +++ b/CInterface/Library/CreatureSpecies.cpp @@ -1,12 +1,13 @@ #include "../../src/Library/CreatureData/CreatureSpecies.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; -export CreatureSpecies* CreatureLib_CreatureSpecies_Construct(uint16_t id, const char* name, - SpeciesVariant* defaultVariant, float genderRatio, - const char* growthRate, uint8_t captureRate) { - return new CreatureSpecies(id, Arbutils::CaseInsensitiveConstString(name), defaultVariant, genderRatio, - Arbutils::CaseInsensitiveConstString(growthRate), captureRate); +export uint8_t CreatureLib_CreatureSpecies_Construct(CreatureSpecies*& out, uint16_t id, const char* name, + SpeciesVariant* defaultVariant, float genderRatio, + const char* growthRate, uint8_t captureRate) { + + Try(out = new CreatureSpecies(id, Arbutils::CaseInsensitiveConstString(name), defaultVariant, genderRatio, + Arbutils::CaseInsensitiveConstString(growthRate), captureRate);) } export void CreatureLib_CreatureSpecies_Destruct(const CreatureSpecies* p) { delete p; } @@ -28,7 +29,7 @@ export bool CreatureLib_CreatureSpecies_HasVariantWithHash(const CreatureSpecies return p->HasVariant(hash); } export bool CreatureLib_CreatureSpecies_TryGetVariant(const CreatureSpecies* p, const char* name, - const SpeciesVariant* out) { + const SpeciesVariant*& out) { return p->TryGetVariant(Arbutils::CaseInsensitiveConstString::GetHash(name), out); } export bool CreatureLib_CreatureSpecies_TryGetVariantWithHash(const CreatureSpecies* p, uint32_t hash, @@ -36,11 +37,13 @@ export bool CreatureLib_CreatureSpecies_TryGetVariantWithHash(const CreatureSpec return p->TryGetVariant(hash, out); } -export const SpeciesVariant* CreatureLib_CreatureSpecies_GetVariant(const CreatureSpecies* p, const char* name) { - return p->GetVariant(Arbutils::CaseInsensitiveConstString::GetHash(name)); +export uint8_t CreatureLib_CreatureSpecies_GetVariant(const SpeciesVariant*& out, const CreatureSpecies* p, + const char* name) { + Try(out = p->GetVariant(Arbutils::CaseInsensitiveConstString::GetHash(name));) } -export const SpeciesVariant* CreatureLib_CreatureSpecies_GetVariantWithHash(const CreatureSpecies* p, uint32_t hash) { - return p->GetVariant(hash); +export uint8_t CreatureLib_CreatureSpecies_GetVariantWithHash(const SpeciesVariant* out, const CreatureSpecies* p, + uint32_t hash) { + Try(out = p->GetVariant(hash);) } #undef SIMPLE_GET_FUNC \ No newline at end of file diff --git a/CInterface/Library/DataLibrary.cpp b/CInterface/Library/DataLibrary.cpp index ec5cd42..c0513ed 100644 --- a/CInterface/Library/DataLibrary.cpp +++ b/CInterface/Library/DataLibrary.cpp @@ -1,11 +1,11 @@ #include "../../src/Library/DataLibrary.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; -export const DataLibrary* CreatureLib_DataLibrary_Construct(LibrarySettings* settings, SpeciesLibrary* species, - AttackLibrary* attacks, ItemLibrary* items, - GrowthRateLibrary* growthRates, TypeLibrary* typeLibrary) { - return new DataLibrary(settings, species, attacks, items, growthRates, typeLibrary); +export uint8_t CreatureLib_DataLibrary_Construct(const DataLibrary*& out, LibrarySettings* settings, + SpeciesLibrary* species, AttackLibrary* attacks, ItemLibrary* items, + GrowthRateLibrary* growthRates, TypeLibrary* typeLibrary) { + Try(out = new DataLibrary(settings, species, attacks, items, growthRates, typeLibrary);) } export void CreatureLib_DataLibrary_Destruct(const DataLibrary* p) { delete p; } diff --git a/CInterface/Library/GrowthRate.cpp b/CInterface/Library/GrowthRate.cpp index dc4d329..630af2f 100644 --- a/CInterface/Library/GrowthRate.cpp +++ b/CInterface/Library/GrowthRate.cpp @@ -1,7 +1,7 @@ #include "../../src/Library/GrowthRates/GrowthRate.hpp" #include "../../src/Library/GrowthRates/ExternGrowthRate.hpp" #include "../../src/Library/GrowthRates/LookupGrowthRate.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; export GrowthRate* CreatureLib_LookupGrowthRate_Construct(uint32_t experiencePerLevel[], size_t count) { @@ -9,17 +9,17 @@ export GrowthRate* CreatureLib_LookupGrowthRate_Construct(uint32_t experiencePer return new LookupGrowthRate(exp); }; -export GrowthRate* CreatureLib_ExternGrowthRate_Construct(uint8_t (*calcLevel)(uint32_t), - uint32_t (*calcExperience)(uint8_t)) { - return new ExternGrowthRate(calcLevel, calcExperience); +export uint8_t CreatureLib_ExternGrowthRate_Construct(GrowthRate*& out, uint8_t (*calcLevel)(uint32_t), + uint32_t (*calcExperience)(uint8_t)) { + Try(out = new ExternGrowthRate(calcLevel, calcExperience);) }; export void CreatureLib_GrowthRate_Destruct(const GrowthRate* p) { delete p; } -export uint8_t CreatureLib_GrowthRate_CalculateLevel(const GrowthRate* p, uint32_t experience) { - return p->CalculateLevel(experience); +export uint8_t CreatureLib_GrowthRate_CalculateLevel(uint8_t& out, const GrowthRate* p, uint32_t experience) { + Try(out = p->CalculateLevel(experience);) } -export uint32_t CreatureLib_GrowthRate_CalculateExperience(const GrowthRate* p, uint8_t level) { - return p->CalculateExperience(level); +export uint8_t CreatureLib_GrowthRate_CalculateExperience(uint32_t& out, const GrowthRate* p, uint8_t level) { + Try(out = p->CalculateExperience(level);) } \ No newline at end of file diff --git a/CInterface/Library/GrowthRateLibrary.cpp b/CInterface/Library/GrowthRateLibrary.cpp index 39ff6e5..ecccdf7 100644 --- a/CInterface/Library/GrowthRateLibrary.cpp +++ b/CInterface/Library/GrowthRateLibrary.cpp @@ -1,5 +1,5 @@ #include "../../src/Library/GrowthRates/GrowthRateLibrary.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; export GrowthRateLibrary* CreatureLib_GrowthRateLibrary_Construct(size_t initialCapacity) { @@ -8,30 +8,30 @@ export GrowthRateLibrary* CreatureLib_GrowthRateLibrary_Construct(size_t initial export void CreatureLib_GrowthRateLibrary_Destruct(GrowthRateLibrary* p) { delete p; } -export uint8_t CreatureLib_GrowthRateLibrary_CalculateLevel(GrowthRateLibrary* library, const char* growthRate, - uint32_t experience) { - return library->CalculateLevel(Arbutils::CaseInsensitiveConstString::GetHash(growthRate), experience); +export uint8_t CreatureLib_GrowthRateLibrary_CalculateLevel(uint8_t& out, GrowthRateLibrary* library, + const char* growthRate, uint32_t experience) { + Try(out = library->CalculateLevel(Arbutils::CaseInsensitiveConstString::GetHash(growthRate), experience);) } -export uint8_t CreatureLib_GrowthRateLibrary_CalculateLevelWithHash(GrowthRateLibrary* library, uint32_t growthRateHash, - uint32_t experience) { - return library->CalculateLevel(growthRateHash, experience); +export uint8_t CreatureLib_GrowthRateLibrary_CalculateLevelWithHash(uint8_t& out, GrowthRateLibrary* library, + uint32_t growthRateHash, uint32_t experience) { + Try(out = library->CalculateLevel(growthRateHash, experience);) } -export uint32_t CreatureLib_GrowthRateLibrary_CalculateExperience(GrowthRateLibrary* library, const char* growthRate, - uint8_t level) { - return library->CalculateExperience(Arbutils::CaseInsensitiveConstString::GetHash(growthRate), level); +export uint8_t CreatureLib_GrowthRateLibrary_CalculateExperience(uint32_t& out, GrowthRateLibrary* library, + const char* growthRate, uint8_t level) { + Try(out = library->CalculateExperience(Arbutils::CaseInsensitiveConstString::GetHash(growthRate), level);) } -export uint32_t CreatureLib_GrowthRateLibrary_CalculateExperienceWithHash(GrowthRateLibrary* library, - uint32_t growthRateHash, uint8_t level) { - return library->CalculateExperience(growthRateHash, level); +export uint8_t CreatureLib_GrowthRateLibrary_CalculateExperienceWithHash(uint32_t& out, GrowthRateLibrary* library, + uint32_t growthRateHash, uint8_t level) { + Try(out = library->CalculateExperience(growthRateHash, level);) } -export void CreatureLib_GrowthRateLibrary_AddGrowthRate(GrowthRateLibrary* library, const char* growthRateName, - GrowthRate* growthRate) { - return library->AddGrowthRate(Arbutils::CaseInsensitiveConstString::GetHash(growthRateName), growthRate); +export uint8_t CreatureLib_GrowthRateLibrary_AddGrowthRate(GrowthRateLibrary* library, const char* growthRateName, + GrowthRate* growthRate) { + Try(library->AddGrowthRate(Arbutils::CaseInsensitiveConstString::GetHash(growthRateName), growthRate);) } -export void CreatureLib_GrowthRateLibrary_AddGrowthRateWithHash(GrowthRateLibrary* library, uint32_t growthRateHash, - GrowthRate* growthRate) { - return library->AddGrowthRate(growthRateHash, growthRate); +export uint8_t CreatureLib_GrowthRateLibrary_AddGrowthRateWithHash(GrowthRateLibrary* library, uint32_t growthRateHash, + GrowthRate* growthRate) { + Try(library->AddGrowthRate(growthRateHash, growthRate);) } diff --git a/CInterface/Library/Item.cpp b/CInterface/Library/Item.cpp index ccb9ca6..6f53bdf 100644 --- a/CInterface/Library/Item.cpp +++ b/CInterface/Library/Item.cpp @@ -1,5 +1,5 @@ #include "../../src/Library/Items/Item.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; using ConstString = Arbutils::CaseInsensitiveConstString; diff --git a/CInterface/Library/ItemLibrary.cpp b/CInterface/Library/ItemLibrary.cpp index d437b6b..dacc26c 100644 --- a/CInterface/Library/ItemLibrary.cpp +++ b/CInterface/Library/ItemLibrary.cpp @@ -1,6 +1,6 @@ #include "../../src/Library/ItemLibrary.hpp" +#include "../Core.hpp" #include "BaseLibrary.cpp" -#define export extern "C" using namespace CreatureLib::Library; export const ItemLibrary* CreatureLib_ItemLibrary_Construct(size_t initialCapacity = 32) { diff --git a/CInterface/Library/LearnableAttacks.cpp b/CInterface/Library/LearnableAttacks.cpp index a3391b8..d3f16f0 100644 --- a/CInterface/Library/LearnableAttacks.cpp +++ b/CInterface/Library/LearnableAttacks.cpp @@ -1,9 +1,9 @@ #include "../../src/Library/CreatureData/LearnableAttacks.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; -export LearnableAttacks* CreatureLib_LearnableAttacks_Construct(size_t levelAttackCapacity) { - return new LearnableAttacks(levelAttackCapacity); +export uint8_t CreatureLib_LearnableAttacks_Construct(LearnableAttacks*& out, size_t levelAttackCapacity) { + Try(out = new LearnableAttacks(levelAttackCapacity);) }; export void CreatureLib_LearnableAttacks_Destruct(LearnableAttacks* p) { delete p; } diff --git a/CInterface/Library/LibrarySettings.cpp b/CInterface/Library/LibrarySettings.cpp index 1a44bc1..f8ef21d 100644 --- a/CInterface/Library/LibrarySettings.cpp +++ b/CInterface/Library/LibrarySettings.cpp @@ -1,5 +1,5 @@ #include "../../src/Library/LibrarySettings.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; export const LibrarySettings* CreatureLib_LibrarySettings_Construct(uint8_t maximalLevel, uint8_t maximalMoves) { diff --git a/CInterface/Library/SpeciesLibrary.cpp b/CInterface/Library/SpeciesLibrary.cpp index 4443800..c631b6c 100644 --- a/CInterface/Library/SpeciesLibrary.cpp +++ b/CInterface/Library/SpeciesLibrary.cpp @@ -1,6 +1,6 @@ #include "../../src/Library/SpeciesLibrary.hpp" +#include "../Core.hpp" #include "BaseLibrary.cpp" -#define export extern "C" using namespace CreatureLib::Library; export const SpeciesLibrary* CreatureLib_SpeciesLibrary_Construct(size_t initialCapacity = 32) { diff --git a/CInterface/Library/SpeciesVariant.cpp b/CInterface/Library/SpeciesVariant.cpp index 3593024..f1ffff2 100644 --- a/CInterface/Library/SpeciesVariant.cpp +++ b/CInterface/Library/SpeciesVariant.cpp @@ -1,5 +1,5 @@ #include "../../src/Library/CreatureData/SpeciesVariant.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; using ConstString = Arbutils::CaseInsensitiveConstString; diff --git a/CInterface/Library/TypeLibrary.cpp b/CInterface/Library/TypeLibrary.cpp index 33dde15..2c3cb2e 100644 --- a/CInterface/Library/TypeLibrary.cpp +++ b/CInterface/Library/TypeLibrary.cpp @@ -1,5 +1,5 @@ #include "../../src/Library/TypeLibrary.hpp" -#define export extern "C" +#include "../Core.hpp" using namespace CreatureLib::Library; export TypeLibrary* CreatureLib_TypeLibrary_Construct(size_t initialCapacity) { @@ -8,30 +8,31 @@ export TypeLibrary* CreatureLib_TypeLibrary_Construct(size_t initialCapacity) { export void CreatureLib_TypeLibrary_Destruct(const TypeLibrary* p) { delete p; } -export uint8_t CreatureLib_TypeLibrary_GetTypeId(const TypeLibrary* p, const char* type) { - return p->GetTypeId(Arbutils::CaseInsensitiveConstString::GetHash(type)); +export uint8_t CreatureLib_TypeLibrary_GetTypeId(uint8_t& out, const TypeLibrary* p, const char* type) { + Try(out = p->GetTypeId(Arbutils::CaseInsensitiveConstString::GetHash(type));) } -export uint8_t CreatureLib_TypeLibrary_GetTypeIdWithHash(const TypeLibrary* p, uint32_t type) { - return p->GetTypeId(type); +export uint8_t CreatureLib_TypeLibrary_GetTypeIdWithHash(uint8_t& out, const TypeLibrary* p, uint32_t type) { + Try(out = p->GetTypeId(type);) } -export uint8_t CreatureLib_TypeLibrary_RegisterType(TypeLibrary* p, const char* type) { - return p->RegisterType(Arbutils::CaseInsensitiveConstString::GetHash(type)); +export uint8_t CreatureLib_TypeLibrary_RegisterType(uint8_t& out, TypeLibrary* p, const char* type) { + Try(out = p->RegisterType(Arbutils::CaseInsensitiveConstString::GetHash(type));) } -export uint8_t CreatureLib_TypeLibrary_RegisterTypeWithHash(TypeLibrary* p, uint32_t type) { - return p->RegisterType(type); +export uint8_t CreatureLib_TypeLibrary_RegisterTypeWithHash(uint8_t& out, TypeLibrary* p, uint32_t type) { + Try(out = p->RegisterType(type);) } -export void CreatureLib_TypeLibrary_SetEffectiveness(TypeLibrary* p, uint8_t attacking, uint8_t defensive, - float effectiveness) { - p->SetEffectiveness(attacking, defensive, effectiveness); +export uint8_t CreatureLib_TypeLibrary_SetEffectiveness(TypeLibrary* p, uint8_t attacking, uint8_t defensive, + float effectiveness) { + Try(p->SetEffectiveness(attacking, defensive, effectiveness);) } -export float CreatureLib_TypeLibrary_GetSingleEffectiveness(TypeLibrary* p, uint8_t attacking, uint8_t defensive) { - return p->GetSingleEffectiveness(attacking, defensive); +export uint8_t CreatureLib_TypeLibrary_GetSingleEffectiveness(float& out, TypeLibrary* p, uint8_t attacking, + uint8_t defensive) { + Try(out = p->GetSingleEffectiveness(attacking, defensive);) } -export float CreatureLib_TypeLibrary_GetEffectiveness(TypeLibrary* p, uint8_t attacking, uint8_t defensive[], - size_t defensiveCount) { - return p->GetEffectiveness(attacking, List(defensive, defensive + defensiveCount)); +export uint8_t CreatureLib_TypeLibrary_GetEffectiveness(float& out, TypeLibrary* p, uint8_t attacking, + uint8_t defensive[], size_t defensiveCount) { + Try(out = p->GetEffectiveness(attacking, List(defensive, defensive + defensiveCount));) } diff --git a/CMakeLists.txt b/CMakeLists.txt index 72608eb..943a664 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,11 +32,11 @@ if (WINDOWS) endif (WINDOWS) # Create main Library library with files in src/Library -file(GLOB_RECURSE LIBRARY_SRC_FILES "src/Library/*.cpp" "src/Library/*.hpp" "CInterface/Library/*.cpp") +file(GLOB_RECURSE LIBRARY_SRC_FILES "src/Library/*.cpp" "src/Library/*.hpp" "CInterface/Library/*.cpp" "CInterface/Core.*") add_library(CreatureLibLibrary SHARED ${LIBRARY_SRC_FILES}) # Create Battling library with files in src/Battling -file(GLOB_RECURSE BATTLING_SRC_FILES "src/Battling/*.cpp" "src/Battling/*.hpp" "CInterface/Battling/*.cpp") +file(GLOB_RECURSE BATTLING_SRC_FILES "src/Battling/*.cpp" "src/Battling/*.hpp" "CInterface/Battling/*.cpp" "CInterface/Core.*") add_library(CreatureLibBattling SHARED ${BATTLING_SRC_FILES}) if (NOT DEFINED CONAN_EXPORTED) diff --git a/extern/catch.hpp b/extern/catch.hpp index e0888b9..5fb1c80 100644 --- a/extern/catch.hpp +++ b/extern/catch.hpp @@ -6377,36 +6377,28 @@ int m_sectionDepth = 0; // User-facing chronometer - // start catch_clock.hpp // Clocks - #include #include namespace Catch { -namespace Benchmark { -template -using ClockDuration = typename Clock::duration; -template -using FloatDuration = std::chrono::duration; + namespace Benchmark { + template using ClockDuration = typename Clock::duration; + template using FloatDuration = std::chrono::duration; -template -using TimePoint = typename Clock::time_point; + template using TimePoint = typename Clock::time_point; -using default_clock = std::chrono::steady_clock; + using default_clock = std::chrono::steady_clock; -template -struct now { -TimePoint operator()() const { -return Clock::now(); -} -}; + template struct now { + TimePoint operator()() const { return Clock::now(); } + }; -using fp_seconds = std::chrono::duration>; -} // namespace Benchmark + using fp_seconds = std::chrono::duration>; + } // namespace Benchmark } // namespace Catch // end catch_clock.hpp @@ -6414,59 +6406,49 @@ using fp_seconds = std::chrono::duration>; // Hinting the optimizer - #if defined(_MSC_VER) -# include // atomic_thread_fence +#include // atomic_thread_fence #endif namespace Catch { -namespace Benchmark { + namespace Benchmark { #if defined(__GNUC__) || defined(__clang__) -template -inline void keep_memory(T* p) { -asm volatile("" : : "g"(p) : "memory"); -} -inline void keep_memory() { -asm volatile("" : : : "memory"); -} + template inline void keep_memory(T* p) { asm volatile("" : : "g"(p) : "memory"); } + inline void keep_memory() { asm volatile("" : : : "memory"); } -namespace Detail { -inline void optimizer_barrier() { keep_memory(); } -} // namespace Detail + namespace Detail { + inline void optimizer_barrier() { keep_memory(); } + } // namespace Detail #elif defined(_MSC_VER) #pragma optimize("", off) -template -inline void keep_memory(T* p) { -// thanks @milleniumbug -*reinterpret_cast(p) = *reinterpret_cast(p); -} + template inline void keep_memory(T* p) { + // thanks @milleniumbug + *reinterpret_cast(p) = *reinterpret_cast(p); + } // TODO equivalent keep_memory() #pragma optimize("", on) -namespace Detail { -inline void optimizer_barrier() { -std::atomic_thread_fence(std::memory_order_seq_cst); -} -} // namespace Detail + namespace Detail { + inline void optimizer_barrier() { std::atomic_thread_fence(std::memory_order_seq_cst); } + } // namespace Detail #endif -template -inline void deoptimize_value(T&& x) { -keep_memory(&x); -} + template inline void deoptimize_value(T&& x) { keep_memory(&x); } -template -inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if::value>::type { -deoptimize_value(std::forward(fn) (std::forward(args...))); -} + template + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> + typename std::enable_if::value>::type { + deoptimize_value(std::forward(fn)(std::forward(args...))); + } -template -inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if::value>::type { -std::forward(fn) (std::forward(args...)); -} -} // namespace Benchmark + template + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> + typename std::enable_if::value>::type { + std::forward(fn)(std::forward(args...)); + } + } // namespace Benchmark } // namespace Catch // end catch_optimizer.hpp @@ -6474,111 +6456,101 @@ std::forward(fn) (std::forward(args...)); // Invoke with a special case for void - #include #include namespace Catch { -namespace Benchmark { -namespace Detail { -template -struct CompleteType { using type = T; }; -template <> -struct CompleteType { struct type {}; }; + namespace Benchmark { + namespace Detail { + template struct CompleteType { using type = T; }; + template <> struct CompleteType { + struct type {}; + }; -template -using CompleteType_t = typename CompleteType::type; + template using CompleteType_t = typename CompleteType::type; -template -struct CompleteInvoker { -template -static Result invoke(Fun&& fun, Args&&... args) { -return std::forward(fun)(std::forward(args)...); -} -}; -template <> -struct CompleteInvoker { -template -static CompleteType_t invoke(Fun&& fun, Args&&... args) { -std::forward(fun)(std::forward(args)...); -return {}; -} -}; -template -using ResultOf_t = typename std::result_of::type; + template struct CompleteInvoker { + template static Result invoke(Fun&& fun, Args&&... args) { + return std::forward(fun)(std::forward(args)...); + } + }; + template <> struct CompleteInvoker { + template + static CompleteType_t invoke(Fun&& fun, Args&&... args) { + std::forward(fun)(std::forward(args)...); + return {}; + } + }; + template using ResultOf_t = typename std::result_of::type; -// invoke and not return void :( -template -CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { -return CompleteInvoker>::invoke(std::forward(fun), std::forward(args)...); -} + // invoke and not return void :( + template + CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker>::invoke(std::forward(fun), + std::forward(args)...); + } -const std::string benchmarkErrorMsg = "a benchmark failed to run successfully"; -} // namespace Detail + const std::string benchmarkErrorMsg = "a benchmark failed to run successfully"; + } // namespace Detail -template -Detail::CompleteType_t> user_code(Fun&& fun) { -CATCH_TRY{ -return Detail::complete_invoke(std::forward(fun)); -} CATCH_CATCH_ALL{ -getResultCapture().benchmarkFailed(translateActiveException()); -CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg); -} -} -} // namespace Benchmark + template Detail::CompleteType_t> user_code(Fun&& fun) { + CATCH_TRY { return Detail::complete_invoke(std::forward(fun)); } + CATCH_CATCH_ALL { + getResultCapture().benchmarkFailed(translateActiveException()); + CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg); + } + } + } // namespace Benchmark } // namespace Catch // end catch_complete_invoke.hpp namespace Catch { -namespace Benchmark { -namespace Detail { -struct ChronometerConcept { -virtual void start() = 0; -virtual void finish() = 0; -virtual ~ChronometerConcept() = default; -}; -template -struct ChronometerModel final : public ChronometerConcept { -void start() override { started = Clock::now(); } -void finish() override { finished = Clock::now(); } + namespace Benchmark { + namespace Detail { + struct ChronometerConcept { + virtual void start() = 0; + virtual void finish() = 0; + virtual ~ChronometerConcept() = default; + }; + template struct ChronometerModel final : public ChronometerConcept { + void start() override { started = Clock::now(); } + void finish() override { finished = Clock::now(); } -ClockDuration elapsed() const { return finished - started; } + ClockDuration elapsed() const { return finished - started; } -TimePoint started; -TimePoint finished; -}; -} // namespace Detail + TimePoint started; + TimePoint finished; + }; + } // namespace Detail -struct Chronometer { -public: -template -void measure(Fun&& fun) { measure(std::forward(fun), is_callable()); } + struct Chronometer { + public: + template void measure(Fun&& fun) { + measure(std::forward(fun), is_callable()); + } -int runs() const { return k; } + int runs() const { return k; } -Chronometer(Detail::ChronometerConcept& meter, int k) -: impl(&meter) -, k(k) {} + Chronometer(Detail::ChronometerConcept& meter, int k) : impl(&meter), k(k) {} -private: -template -void measure(Fun&& fun, std::false_type) { -measure([&fun](int) { return fun(); }, std::true_type()); -} + private: + template void measure(Fun&& fun, std::false_type) { + measure([&fun](int) { return fun(); }, std::true_type()); + } -template -void measure(Fun&& fun, std::true_type) { -Detail::optimizer_barrier(); -impl->start(); -for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i); -impl->finish(); -Detail::optimizer_barrier(); -} + template void measure(Fun&& fun, std::true_type) { + Detail::optimizer_barrier(); + impl->start(); + for (int i = 0; i < k; ++i) + invoke_deoptimized(fun, i); + impl->finish(); + Detail::optimizer_barrier(); + } -Detail::ChronometerConcept* impl; -int k; -}; -} // namespace Benchmark + Detail::ChronometerConcept* impl; + int k; + }; + } // namespace Benchmark } // namespace Catch // end catch_chronometer.hpp @@ -6586,26 +6558,20 @@ int k; // Environment information - namespace Catch { -namespace Benchmark { -template -struct EnvironmentEstimate { -Duration mean; -OutlierClassification outliers; + namespace Benchmark { + template struct EnvironmentEstimate { + Duration mean; + OutlierClassification outliers; -template -operator EnvironmentEstimate() const { -return { mean, outliers }; -} -}; -template -struct Environment { -using clock_type = Clock; -EnvironmentEstimate> clock_resolution; -EnvironmentEstimate> clock_cost; -}; -} // namespace Benchmark + template operator EnvironmentEstimate() const { return {mean, outliers}; } + }; + template struct Environment { + using clock_type = Clock; + EnvironmentEstimate> clock_resolution; + EnvironmentEstimate> clock_cost; + }; + } // namespace Benchmark } // namespace Catch // end catch_environment.hpp @@ -6613,97 +6579,82 @@ EnvironmentEstimate> clock_cost; // Execution plan - // start catch_benchmark_function.hpp // Dumb std::function implementation for consistent call overhead - #include +#include #include #include -#include namespace Catch { -namespace Benchmark { -namespace Detail { -template -using Decay = typename std::decay::type; -template -struct is_related -: std::is_same, Decay> {}; + namespace Benchmark { + namespace Detail { + template using Decay = typename std::decay::type; + template struct is_related : std::is_same, Decay> {}; -/// We need to reinvent std::function because every piece of code that might add overhead -/// in a measurement context needs to have consistent performance characteristics so that we -/// can account for it in the measurement. -/// Implementations of std::function with optimizations that aren't always applicable, like -/// small buffer optimizations, are not uncommon. -/// This is effectively an implementation of std::function without any such optimizations; -/// it may be slow, but it is consistently slow. -struct BenchmarkFunction { -private: -struct callable { -virtual void call(Chronometer meter) const = 0; -virtual callable* clone() const = 0; -virtual ~callable() = default; -}; -template -struct model : public callable { -model(Fun&& fun) : fun(std::move(fun)) {} -model(Fun const& fun) : fun(fun) {} + /// We need to reinvent std::function because every piece of code that might add overhead + /// in a measurement context needs to have consistent performance characteristics so that we + /// can account for it in the measurement. + /// Implementations of std::function with optimizations that aren't always applicable, like + /// small buffer optimizations, are not uncommon. + /// This is effectively an implementation of std::function without any such optimizations; + /// it may be slow, but it is consistently slow. + struct BenchmarkFunction { + private: + struct callable { + virtual void call(Chronometer meter) const = 0; + virtual callable* clone() const = 0; + virtual ~callable() = default; + }; + template struct model : public callable { + model(Fun&& fun) : fun(std::move(fun)) {} + model(Fun const& fun) : fun(fun) {} -model* clone() const override { return new model(*this); } + model* clone() const override { return new model(*this); } -void call(Chronometer meter) const override { -call(meter, is_callable()); -} -void call(Chronometer meter, std::true_type) const { -fun(meter); -} -void call(Chronometer meter, std::false_type) const { -meter.measure(fun); -} + void call(Chronometer meter) const override { call(meter, is_callable()); } + void call(Chronometer meter, std::true_type) const { fun(meter); } + void call(Chronometer meter, std::false_type) const { meter.measure(fun); } -Fun fun; -}; + Fun fun; + }; -struct do_nothing { void operator()() const {} }; + struct do_nothing { + void operator()() const {} + }; -template -BenchmarkFunction(model* c) : f(c) {} + template BenchmarkFunction(model* c) : f(c) {} -public: -BenchmarkFunction() -: f(new model{ {} }) {} + public: + BenchmarkFunction() : f(new model{{}}) {} -template ::value, int>::type = 0> -BenchmarkFunction(Fun&& fun) -: f(new model::type>(std::forward(fun))) {} + template ::value, int>::type = 0> + BenchmarkFunction(Fun&& fun) : f(new model::type>(std::forward(fun))) {} -BenchmarkFunction(BenchmarkFunction&& that) -: f(std::move(that.f)) {} + BenchmarkFunction(BenchmarkFunction&& that) : f(std::move(that.f)) {} -BenchmarkFunction(BenchmarkFunction const& that) -: f(that.f->clone()) {} + BenchmarkFunction(BenchmarkFunction const& that) : f(that.f->clone()) {} -BenchmarkFunction& operator=(BenchmarkFunction&& that) { -f = std::move(that.f); -return *this; -} + BenchmarkFunction& operator=(BenchmarkFunction&& that) { + f = std::move(that.f); + return *this; + } -BenchmarkFunction& operator=(BenchmarkFunction const& that) { -f.reset(that.f->clone()); -return *this; -} + BenchmarkFunction& operator=(BenchmarkFunction const& that) { + f.reset(that.f->clone()); + return *this; + } -void operator()(Chronometer meter) const { f->call(meter); } + void operator()(Chronometer meter) const { f->call(meter); } -private: -std::unique_ptr f; -}; -} // namespace Detail -} // namespace Benchmark + private: + std::unique_ptr f; + }; + } // namespace Detail + } // namespace Benchmark } // namespace Catch // end catch_benchmark_function.hpp @@ -6711,161 +6662,156 @@ std::unique_ptr f; // repeat algorithm - #include #include namespace Catch { -namespace Benchmark { -namespace Detail { -template -struct repeater { -void operator()(int k) const { -for (int i = 0; i < k; ++i) { -fun(); -} -} -Fun fun; -}; -template -repeater::type> repeat(Fun&& fun) { -return { std::forward(fun) }; -} -} // namespace Detail -} // namespace Benchmark + namespace Benchmark { + namespace Detail { + template struct repeater { + void operator()(int k) const { + for (int i = 0; i < k; ++i) { + fun(); + } + } + Fun fun; + }; + template repeater::type> repeat(Fun&& fun) { + return {std::forward(fun)}; + } + } // namespace Detail + } // namespace Benchmark } // namespace Catch // end catch_repeat.hpp // start catch_run_for_at_least.hpp -// Run a function for a minimum amount of time - +// Try a function for a minimum amount of time // start catch_measure.hpp // Measure - // start catch_timing.hpp // Timing - #include #include namespace Catch { -namespace Benchmark { -template -struct Timing { -Duration elapsed; -Result result; -int iterations; -}; -template -using TimingOf = Timing, Detail::CompleteType_t>>; -} // namespace Benchmark + namespace Benchmark { + template struct Timing { + Duration elapsed; + Result result; + int iterations; + }; + template + using TimingOf = Timing, Detail::CompleteType_t>>; + } // namespace Benchmark } // namespace Catch // end catch_timing.hpp #include namespace Catch { -namespace Benchmark { -namespace Detail { -template -TimingOf measure(Fun&& fun, Args&&... args) { -auto start = Clock::now(); -auto&& r = Detail::complete_invoke(fun, std::forward(args)...); -auto end = Clock::now(); -auto delta = end - start; -return { delta, std::forward(r), 1 }; -} -} // namespace Detail -} // namespace Benchmark + namespace Benchmark { + namespace Detail { + template + TimingOf measure(Fun&& fun, Args&&... args) { + auto start = Clock::now(); + auto&& r = Detail::complete_invoke(fun, std::forward(args)...); + auto end = Clock::now(); + auto delta = end - start; + return {delta, std::forward(r), 1}; + } + } // namespace Detail + } // namespace Benchmark } // namespace Catch // end catch_measure.hpp -#include #include +#include namespace Catch { -namespace Benchmark { -namespace Detail { -template -TimingOf measure_one(Fun&& fun, int iters, std::false_type) { -return Detail::measure(fun, iters); -} -template -TimingOf measure_one(Fun&& fun, int iters, std::true_type) { -Detail::ChronometerModel meter; -auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); + namespace Benchmark { + namespace Detail { + template + TimingOf measure_one(Fun&& fun, int iters, std::false_type) { + return Detail::measure(fun, iters); + } + template + TimingOf measure_one(Fun&& fun, int iters, std::true_type) { + Detail::ChronometerModel meter; + auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); -return { meter.elapsed(), std::move(result), iters }; -} + return {meter.elapsed(), std::move(result), iters}; + } -template -using run_for_at_least_argument_t = typename std::conditional::value, Chronometer, int>::type; + template + using run_for_at_least_argument_t = + typename std::conditional::value, Chronometer, int>::type; -struct optimized_away_error : std::exception { -const char* what() const noexcept override { -return "could not measure benchmark, maybe it was optimized away"; -} -}; + struct optimized_away_error : std::exception { + const char* what() const noexcept override { + return "could not measure benchmark, maybe it was optimized away"; + } + }; -template -TimingOf)> run_for_at_least(ClockDuration how_long, int seed, Fun&& fun) { -auto iters = seed; -while (iters < (1 << 30)) { -auto&& Timing = measure_one(fun, iters, is_callable()); + template + TimingOf)> + run_for_at_least(ClockDuration how_long, int seed, Fun&& fun) { + auto iters = seed; + while (iters < (1 << 30)) { + auto&& Timing = measure_one(fun, iters, is_callable()); -if (Timing.elapsed >= how_long) { -return { Timing.elapsed, std::move(Timing.result), iters }; -} -iters *= 2; -} -throw optimized_away_error{}; -} -} // namespace Detail -} // namespace Benchmark + if (Timing.elapsed >= how_long) { + return {Timing.elapsed, std::move(Timing.result), iters}; + } + iters *= 2; + } + throw optimized_away_error{}; + } + } // namespace Detail + } // namespace Benchmark } // namespace Catch // end catch_run_for_at_least.hpp #include namespace Catch { -namespace Benchmark { -template -struct ExecutionPlan { -int iterations_per_sample; -Duration estimated_duration; -Detail::BenchmarkFunction benchmark; -Duration warmup_time; -int warmup_iterations; + namespace Benchmark { + template struct ExecutionPlan { + int iterations_per_sample; + Duration estimated_duration; + Detail::BenchmarkFunction benchmark; + Duration warmup_time; + int warmup_iterations; -template -operator ExecutionPlan() const { -return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; -} + template operator ExecutionPlan() const { + return {iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations}; + } -template -std::vector> run(const IConfig &cfg, Environment> env) const { -// warmup a bit -Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); + template + std::vector> run(const IConfig& cfg, Environment> env) const { + // warmup a bit + Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), + warmup_iterations, Detail::repeat(now{})); -std::vector> times; -times.reserve(cfg.benchmarkSamples()); -std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { -Detail::ChronometerModel model; -this->benchmark(Chronometer(model, iterations_per_sample)); -auto sample_time = model.elapsed() - env.clock_cost.mean; -if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); -return sample_time / iterations_per_sample; -}); -return times; -} -}; -} // namespace Benchmark + std::vector> times; + times.reserve(cfg.benchmarkSamples()); + std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { + Detail::ChronometerModel model; + this->benchmark(Chronometer(model, iterations_per_sample)); + auto sample_time = model.elapsed() - env.clock_cost.mean; + if (sample_time < FloatDuration::zero()) + sample_time = FloatDuration::zero(); + return sample_time / iterations_per_sample; + }); + return times; + } + }; + } // namespace Benchmark } // namespace Catch // end catch_execution_plan.hpp @@ -6873,286 +6819,289 @@ return times; // Environment measurement - // start catch_stats.hpp // Statistical analysis tools - #include +#include +#include #include -#include #include #include -#include #include -#include +#include namespace Catch { -namespace Benchmark { -namespace Detail { -using sample = std::vector; + namespace Benchmark { + namespace Detail { + using sample = std::vector; -double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last); + double weighted_average_quantile(int k, int q, std::vector::iterator first, + std::vector::iterator last); -template -OutlierClassification classify_outliers(Iterator first, Iterator last) { -std::vector copy(first, last); + template OutlierClassification classify_outliers(Iterator first, Iterator last) { + std::vector copy(first, last); -auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); -auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); -auto iqr = q3 - q1; -auto los = q1 - (iqr * 3.); -auto lom = q1 - (iqr * 1.5); -auto him = q3 + (iqr * 1.5); -auto his = q3 + (iqr * 3.); + auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); + auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); + auto iqr = q3 - q1; + auto los = q1 - (iqr * 3.); + auto lom = q1 - (iqr * 1.5); + auto him = q3 + (iqr * 1.5); + auto his = q3 + (iqr * 3.); -OutlierClassification o; -for (; first != last; ++first) { -auto&& t = *first; -if (t < los) ++o.low_severe; -else if (t < lom) ++o.low_mild; -else if (t > his) ++o.high_severe; -else if (t > him) ++o.high_mild; -++o.samples_seen; -} -return o; -} + OutlierClassification o; + for (; first != last; ++first) { + auto&& t = *first; + if (t < los) + ++o.low_severe; + else if (t < lom) + ++o.low_mild; + else if (t > his) + ++o.high_severe; + else if (t > him) + ++o.high_mild; + ++o.samples_seen; + } + return o; + } -template -double mean(Iterator first, Iterator last) { -auto count = last - first; -double sum = std::accumulate(first, last, 0.); -return sum / count; -} + template double mean(Iterator first, Iterator last) { + auto count = last - first; + double sum = std::accumulate(first, last, 0.); + return sum / count; + } -template -sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) { -auto n = last - first; -std::uniform_int_distribution dist(0, n - 1); + template + sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) { + auto n = last - first; + std::uniform_int_distribution dist(0, n - 1); -sample out; -out.reserve(resamples); -std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { -std::vector resampled; -resampled.reserve(n); -std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; }); -return estimator(resampled.begin(), resampled.end()); -}); -std::sort(out.begin(), out.end()); -return out; -} + sample out; + out.reserve(resamples); + std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { + std::vector resampled; + resampled.reserve(n); + std::generate_n(std::back_inserter(resampled), n, + [first, &dist, &rng] { return first[dist(rng)]; }); + return estimator(resampled.begin(), resampled.end()); + }); + std::sort(out.begin(), out.end()); + return out; + } -template -sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { -auto n = last - first; -auto second = std::next(first); -sample results; -results.reserve(n); + template + sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { + auto n = last - first; + auto second = std::next(first); + sample results; + results.reserve(n); -for (auto it = first; it != last; ++it) { -std::iter_swap(it, first); -results.push_back(estimator(second, last)); -} + for (auto it = first; it != last; ++it) { + std::iter_swap(it, first); + results.push_back(estimator(second, last)); + } -return results; -} + return results; + } -inline double normal_cdf(double x) { -return std::erfc(-x / std::sqrt(2.0)) / 2.0; -} + inline double normal_cdf(double x) { return std::erfc(-x / std::sqrt(2.0)) / 2.0; } -double erfc_inv(double x); + double erfc_inv(double x); -double normal_quantile(double p); + double normal_quantile(double p); -template -Estimate bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { -auto n_samples = last - first; + template + Estimate bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, + Estimator&& estimator) { + auto n_samples = last - first; -double point = estimator(first, last); -// Degenerate case with a single sample -if (n_samples == 1) return { point, point, point, confidence_level }; + double point = estimator(first, last); + // Degenerate case with a single sample + if (n_samples == 1) + return {point, point, point, confidence_level}; -sample jack = jackknife(estimator, first, last); -double jack_mean = mean(jack.begin(), jack.end()); -double sum_squares, sum_cubes; -std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair sqcb, double x) -> std::pair { -auto d = jack_mean - x; -auto d2 = d * d; -auto d3 = d2 * d; -return { sqcb.first + d2, sqcb.second + d3 }; -}); + sample jack = jackknife(estimator, first, last); + double jack_mean = mean(jack.begin(), jack.end()); + double sum_squares, sum_cubes; + std::tie(sum_squares, sum_cubes) = + std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), + [jack_mean](std::pair sqcb, double x) -> std::pair { + auto d = jack_mean - x; + auto d2 = d * d; + auto d3 = d2 * d; + return {sqcb.first + d2, sqcb.second + d3}; + }); -double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); -int n = static_cast(resample.size()); -double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n; -// degenerate case with uniform samples -if (prob_n == 0) return { point, point, point, confidence_level }; + double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); + int n = static_cast(resample.size()); + double prob_n = + std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / + (double)n; + // degenerate case with uniform samples + if (prob_n == 0) + return {point, point, point, confidence_level}; -double bias = normal_quantile(prob_n); -double z1 = normal_quantile((1. - confidence_level) / 2.); + double bias = normal_quantile(prob_n); + double z1 = normal_quantile((1. - confidence_level) / 2.); -auto cumn = [n](double x) -> int { -return std::lround(normal_cdf(x) * n); }; -auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; -double b1 = bias + z1; -double b2 = bias - z1; -double a1 = a(b1); -double a2 = a(b2); -auto lo = std::max(cumn(a1), 0); -auto hi = std::min(cumn(a2), n - 1); + auto cumn = [n](double x) -> int { return std::lround(normal_cdf(x) * n); }; + auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; + double b1 = bias + z1; + double b2 = bias - z1; + double a1 = a(b1); + double a2 = a(b2); + auto lo = std::max(cumn(a1), 0); + auto hi = std::min(cumn(a2), n - 1); -return { point, resample[lo], resample[hi], confidence_level }; -} + return {point, resample[lo], resample[hi], confidence_level}; + } -double outlier_variance(Estimate mean, Estimate stddev, int n); + double outlier_variance(Estimate mean, Estimate stddev, int n); -struct bootstrap_analysis { -Estimate mean; -Estimate standard_deviation; -double outlier_variance; -}; + struct bootstrap_analysis { + Estimate mean; + Estimate standard_deviation; + double outlier_variance; + }; -bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector::iterator first, std::vector::iterator last); -} // namespace Detail -} // namespace Benchmark + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, + std::vector::iterator first, std::vector::iterator last); + } // namespace Detail + } // namespace Benchmark } // namespace Catch // end catch_stats.hpp #include +#include #include #include #include -#include namespace Catch { -namespace Benchmark { -namespace Detail { -template -std::vector resolution(int k) { -std::vector> times; -times.reserve(k + 1); -std::generate_n(std::back_inserter(times), k + 1, now{}); + namespace Benchmark { + namespace Detail { + template std::vector resolution(int k) { + std::vector> times; + times.reserve(k + 1); + std::generate_n(std::back_inserter(times), k + 1, now{}); -std::vector deltas; -deltas.reserve(k); -std::transform(std::next(times.begin()), times.end(), times.begin(), -std::back_inserter(deltas), -[](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); + std::vector deltas; + deltas.reserve(k); + std::transform( + std::next(times.begin()), times.end(), times.begin(), std::back_inserter(deltas), + [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); -return deltas; -} + return deltas; + } -const auto warmup_iterations = 10000; -const auto warmup_time = std::chrono::milliseconds(100); -const auto minimum_ticks = 1000; -const auto warmup_seed = 10000; -const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); -const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); -const auto clock_cost_estimation_tick_limit = 100000; -const auto clock_cost_estimation_time = std::chrono::milliseconds(10); -const auto clock_cost_estimation_iterations = 10000; + const auto warmup_iterations = 10000; + const auto warmup_time = std::chrono::milliseconds(100); + const auto minimum_ticks = 1000; + const auto warmup_seed = 10000; + const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); + const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); + const auto clock_cost_estimation_tick_limit = 100000; + const auto clock_cost_estimation_time = std::chrono::milliseconds(10); + const auto clock_cost_estimation_iterations = 10000; -template -int warmup() { -return run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_seed, &resolution) -.iterations; -} -template -EnvironmentEstimate> estimate_clock_resolution(int iterations) { -auto r = run_for_at_least(std::chrono::duration_cast>(clock_resolution_estimation_time), iterations, &resolution) -.result; -return { -FloatDuration(mean(r.begin(), r.end())), -classify_outliers(r.begin(), r.end()), -}; -} -template -EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { -auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration(clock_cost_estimation_time_limit)); -auto time_clock = [](int k) { -return Detail::measure([k] { -for (int i = 0; i < k; ++i) { -volatile auto ignored = Clock::now(); -(void)ignored; -} -}).elapsed; -}; -time_clock(1); -int iters = clock_cost_estimation_iterations; -auto&& r = run_for_at_least(std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); -std::vector times; -int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); -times.reserve(nsamples); -std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { -return static_cast((time_clock(r.iterations) / r.iterations).count()); -}); -return { -FloatDuration(mean(times.begin(), times.end())), -classify_outliers(times.begin(), times.end()), -}; -} + template int warmup() { + return run_for_at_least(std::chrono::duration_cast>(warmup_time), + warmup_seed, &resolution) + .iterations; + } + template + EnvironmentEstimate> estimate_clock_resolution(int iterations) { + auto r = run_for_at_least( + std::chrono::duration_cast>(clock_resolution_estimation_time), + iterations, &resolution) + .result; + return { + FloatDuration(mean(r.begin(), r.end())), + classify_outliers(r.begin(), r.end()), + }; + } + template + EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { + auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, + FloatDuration(clock_cost_estimation_time_limit)); + auto time_clock = [](int k) { + return Detail::measure([k] { + for (int i = 0; i < k; ++i) { + volatile auto ignored = Clock::now(); + (void)ignored; + } + }) + .elapsed; + }; + time_clock(1); + int iters = clock_cost_estimation_iterations; + auto&& r = run_for_at_least( + std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); + std::vector times; + int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); + times.reserve(nsamples); + std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { + return static_cast((time_clock(r.iterations) / r.iterations).count()); + }); + return { + FloatDuration(mean(times.begin(), times.end())), + classify_outliers(times.begin(), times.end()), + }; + } -template -Environment> measure_environment() { -static Environment>* env = nullptr; -if (env) { -return *env; -} + template Environment> measure_environment() { + static Environment>* env = nullptr; + if (env) { + return *env; + } -auto iters = Detail::warmup(); -auto resolution = Detail::estimate_clock_resolution(iters); -auto cost = Detail::estimate_clock_cost(resolution.mean); + auto iters = Detail::warmup(); + auto resolution = Detail::estimate_clock_resolution(iters); + auto cost = Detail::estimate_clock_cost(resolution.mean); -env = new Environment>{ resolution, cost }; -return *env; -} -} // namespace Detail -} // namespace Benchmark + env = new Environment>{resolution, cost}; + return *env; + } + } // namespace Detail + } // namespace Benchmark } // namespace Catch // end catch_estimate_clock.hpp // start catch_analyse.hpp -// Run and analyse one benchmark - +// Try and analyse one benchmark // start catch_sample_analysis.hpp // Benchmark results - #include -#include -#include #include +#include +#include namespace Catch { -namespace Benchmark { -template -struct SampleAnalysis { -std::vector samples; -Estimate mean; -Estimate standard_deviation; -OutlierClassification outliers; -double outlier_variance; + namespace Benchmark { + template struct SampleAnalysis { + std::vector samples; + Estimate mean; + Estimate standard_deviation; + OutlierClassification outliers; + double outlier_variance; -template -operator SampleAnalysis() const { -std::vector samples2; -samples2.reserve(samples.size()); -std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); -return { -std::move(samples2), -mean, -standard_deviation, -outliers, -outlier_variance, -}; -} -}; -} // namespace Benchmark + template operator SampleAnalysis() const { + std::vector samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), + [](Duration d) { return Duration2(d); }); + return { + std::move(samples2), mean, standard_deviation, outliers, outlier_variance, + }; + } + }; + } // namespace Benchmark } // namespace Catch // end catch_sample_analysis.hpp @@ -7161,219 +7110,196 @@ outlier_variance, #include namespace Catch { -namespace Benchmark { -namespace Detail { -template -SampleAnalysis analyse(const IConfig &cfg, Environment, Iterator first, Iterator last) { -if (!cfg.benchmarkNoAnalysis()) { -std::vector samples; -samples.reserve(last - first); -std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); + namespace Benchmark { + namespace Detail { + template + SampleAnalysis analyse(const IConfig& cfg, Environment, Iterator first, Iterator last) { + if (!cfg.benchmarkNoAnalysis()) { + std::vector samples; + samples.reserve(last - first); + std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); -auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); -auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); + auto analysis = Catch::Benchmark::Detail::analyse_samples( + cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); + auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); -auto wrap_estimate = [](Estimate e) { -return Estimate { -Duration(e.point), -Duration(e.lower_bound), -Duration(e.upper_bound), -e.confidence_interval, -}; -}; -std::vector samples2; -samples2.reserve(samples.size()); -std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); -return { -std::move(samples2), -wrap_estimate(analysis.mean), -wrap_estimate(analysis.standard_deviation), -outliers, -analysis.outlier_variance, -}; -} else { -std::vector samples; -samples.reserve(last - first); + auto wrap_estimate = [](Estimate e) { + return Estimate{ + Duration(e.point), + Duration(e.lower_bound), + Duration(e.upper_bound), + e.confidence_interval, + }; + }; + std::vector samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), + [](double d) { return Duration(d); }); + return { + std::move(samples2), + wrap_estimate(analysis.mean), + wrap_estimate(analysis.standard_deviation), + outliers, + analysis.outlier_variance, + }; + } else { + std::vector samples; + samples.reserve(last - first); -Duration mean = Duration(0); -int i = 0; -for (auto it = first; it < last; ++it, ++i) { -samples.push_back(Duration(*it)); -mean += Duration(*it); -} -mean /= i; + Duration mean = Duration(0); + int i = 0; + for (auto it = first; it < last; ++it, ++i) { + samples.push_back(Duration(*it)); + mean += Duration(*it); + } + mean /= i; -return { -std::move(samples), -Estimate{mean, mean, mean, 0.0}, -Estimate{Duration(0), Duration(0), Duration(0), 0.0}, -OutlierClassification{}, -0.0 -}; -} -} -} // namespace Detail -} // namespace Benchmark + return {std::move(samples), Estimate{mean, mean, mean, 0.0}, + Estimate{Duration(0), Duration(0), Duration(0), 0.0}, OutlierClassification{}, + 0.0}; + } + } + } // namespace Detail + } // namespace Benchmark } // namespace Catch // end catch_analyse.hpp #include +#include #include #include #include -#include namespace Catch { -namespace Benchmark { -struct Benchmark { -Benchmark(std::string &&name) -: name(std::move(name)) {} + namespace Benchmark { + struct Benchmark { + Benchmark(std::string&& name) : name(std::move(name)) {} -template -Benchmark(std::string &&name, FUN &&func) -: fun(std::move(func)), name(std::move(name)) {} + template + Benchmark(std::string&& name, FUN&& func) : fun(std::move(func)), name(std::move(name)) {} -template -ExecutionPlan> prepare(const IConfig &cfg, Environment> env) const { -auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; -auto run_time = std::max(min_time, std::chrono::duration_cast(Detail::warmup_time)); -auto&& test = Detail::run_for_at_least(std::chrono::duration_cast>(run_time), 1, fun); -int new_iters = static_cast(std::ceil(min_time * test.iterations / test.elapsed)); -return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast>(Detail::warmup_time), Detail::warmup_iterations }; -} + template + ExecutionPlan> prepare(const IConfig& cfg, + Environment> env) const { + auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; + auto run_time = std::max(min_time, std::chrono::duration_cast(Detail::warmup_time)); + auto&& test = + Detail::run_for_at_least(std::chrono::duration_cast>(run_time), 1, fun); + int new_iters = static_cast(std::ceil(min_time * test.iterations / test.elapsed)); + return {new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, + std::chrono::duration_cast>(Detail::warmup_time), + Detail::warmup_iterations}; + } -template -void run() { -IConfigPtr cfg = getCurrentContext().getConfig(); + template void run() { + IConfigPtr cfg = getCurrentContext().getConfig(); -auto env = Detail::measure_environment(); + auto env = Detail::measure_environment(); -getResultCapture().benchmarkPreparing(name); -CATCH_TRY{ -auto plan = user_code([&] { -return prepare(*cfg, env); -}); + getResultCapture().benchmarkPreparing(name); + CATCH_TRY { + auto plan = user_code([&] { return prepare(*cfg, env); }); -BenchmarkInfo info { -name, -plan.estimated_duration.count(), -plan.iterations_per_sample, -cfg->benchmarkSamples(), -cfg->benchmarkResamples(), -env.clock_resolution.mean.count(), -env.clock_cost.mean.count() -}; + BenchmarkInfo info{name, + plan.estimated_duration.count(), + plan.iterations_per_sample, + cfg->benchmarkSamples(), + cfg->benchmarkResamples(), + env.clock_resolution.mean.count(), + env.clock_cost.mean.count()}; -getResultCapture().benchmarkStarting(info); + getResultCapture().benchmarkStarting(info); -auto samples = user_code([&] { -return plan.template run(*cfg, env); -}); + auto samples = user_code([&] { return plan.template run(*cfg, env); }); -auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); -BenchmarkStats> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; -getResultCapture().benchmarkEnded(stats); + auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); + BenchmarkStats> stats{info, + analysis.samples, + analysis.mean, + analysis.standard_deviation, + analysis.outliers, + analysis.outlier_variance}; + getResultCapture().benchmarkEnded(stats); + } + CATCH_CATCH_ALL { + if (translateActiveException() != + Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow. + std::rethrow_exception(std::current_exception()); + } + } -} CATCH_CATCH_ALL{ -if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow. -std::rethrow_exception(std::current_exception()); -} -} + // sets lambda to be used in fun *and* executes benchmark! + template ::value, int>::type = 0> + Benchmark& operator=(Fun func) { + fun = Detail::BenchmarkFunction(func); + run(); + return *this; + } -// sets lambda to be used in fun *and* executes benchmark! -template ::value, int>::type = 0> -Benchmark & operator=(Fun func) { -fun = Detail::BenchmarkFunction(func); -run(); -return *this; -} + explicit operator bool() { return true; } -explicit operator bool() { -return true; -} - -private: -Detail::BenchmarkFunction fun; -std::string name; -}; -} + private: + Detail::BenchmarkFunction fun; + std::string name; + }; + } } // namespace Catch #define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1 #define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2 -#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\ - if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ - BenchmarkName = [&](int benchmarkIndex) +#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex) \ + if (Catch::Benchmark::Benchmark BenchmarkName{name}) \ + BenchmarkName = [&](int benchmarkIndex) -#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\ - if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ - BenchmarkName = [&] +#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name) \ + if (Catch::Benchmark::Benchmark BenchmarkName{name}) \ + BenchmarkName = [&] // end catch_benchmark.hpp // start catch_constructor.hpp // Constructor and destructor helpers - #include namespace Catch { -namespace Detail { -template -struct ObjectStorage -{ -using TStorage = typename std::aligned_storage::value>::type; + namespace Detail { + template struct ObjectStorage { + using TStorage = typename std::aligned_storage::value>::type; -ObjectStorage() : data() {} + ObjectStorage() : data() {} -ObjectStorage(const ObjectStorage& other) -{ -new(&data) T(other.stored_object()); -} + ObjectStorage(const ObjectStorage& other) { new (&data) T(other.stored_object()); } -ObjectStorage(ObjectStorage&& other) -{ -new(&data) T(std::move(other.stored_object())); -} + ObjectStorage(ObjectStorage&& other) { new (&data) T(std::move(other.stored_object())); } -~ObjectStorage() { destruct_on_exit(); } + ~ObjectStorage() { destruct_on_exit(); } -template -void construct(Args&&... args) -{ -new (&data) T(std::forward(args)...); -} + template void construct(Args&&... args) { new (&data) T(std::forward(args)...); } -template -typename std::enable_if::type destruct() -{ -stored_object().~T(); -} + template + typename std::enable_if::type destruct() { + stored_object().~T(); + } -private: -// If this is a constructor benchmark, destruct the underlying object -template -void destruct_on_exit(typename std::enable_if::type* = 0) { destruct(); } -// Otherwise, don't -template -void destruct_on_exit(typename std::enable_if::type* = 0) { } + private: + // If this is a constructor benchmark, destruct the underlying object + template void destruct_on_exit(typename std::enable_if::type* = 0) { + destruct(); + } + // Otherwise, don't + template void destruct_on_exit(typename std::enable_if::type* = 0) {} -T& stored_object() -{ -return *static_cast(static_cast(&data)); -} + T& stored_object() { return *static_cast(static_cast(&data)); } -TStorage data; -}; -} + TStorage data; + }; + } -template -using storage_for = Detail::ObjectStorage; + template using storage_for = Detail::ObjectStorage; -template -using destructable_object = Detail::ObjectStorage; + template using destructable_object = Detail::ObjectStorage; } // end catch_constructor.hpp @@ -7393,148 +7319,144 @@ using destructable_object = Detail::ObjectStorage; // Keep these here for external reporters // start catch_test_case_tracker.h +#include #include #include -#include namespace Catch { -namespace TestCaseTracking { + namespace TestCaseTracking { -struct NameAndLocation { -std::string name; -SourceLineInfo location; + struct NameAndLocation { + std::string name; + SourceLineInfo location; -NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); -}; + NameAndLocation(std::string const& _name, SourceLineInfo const& _location); + }; -struct ITracker; + struct ITracker; -using ITrackerPtr = std::shared_ptr; + using ITrackerPtr = std::shared_ptr; -struct ITracker { -virtual ~ITracker(); + struct ITracker { + virtual ~ITracker(); -// static queries -virtual NameAndLocation const& nameAndLocation() const = 0; + // static queries + virtual NameAndLocation const& nameAndLocation() const = 0; -// dynamic queries -virtual bool isComplete() const = 0; // Successfully completed or failed -virtual bool isSuccessfullyCompleted() const = 0; -virtual bool isOpen() const = 0; // Started but not complete -virtual bool hasChildren() const = 0; + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; -virtual ITracker& parent() = 0; + virtual ITracker& parent() = 0; -// actions -virtual void close() = 0; // Successfully complete -virtual void fail() = 0; -virtual void markAsNeedingAnotherRun() = 0; + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; -virtual void addChild( ITrackerPtr const& child ) = 0; -virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; -virtual void openChild() = 0; + virtual void addChild(ITrackerPtr const& child) = 0; + virtual ITrackerPtr findChild(NameAndLocation const& nameAndLocation) = 0; + virtual void openChild() = 0; -// Debug/ checking -virtual bool isSectionTracker() const = 0; -virtual bool isGeneratorTracker() const = 0; -}; + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isGeneratorTracker() const = 0; + }; -class TrackerContext { + class TrackerContext { -enum RunState { -NotStarted, -Executing, -CompletedCycle -}; + enum RunState { NotStarted, Executing, CompletedCycle }; -ITrackerPtr m_rootTracker; -ITracker* m_currentTracker = nullptr; -RunState m_runState = NotStarted; + ITrackerPtr m_rootTracker; + ITracker* m_currentTracker = nullptr; + RunState m_runState = NotStarted; -public: + public: + ITracker& startRun(); + void endRun(); -ITracker& startRun(); -void endRun(); + void startCycle(); + void completeCycle(); -void startCycle(); -void completeCycle(); + bool completedCycle() const; + ITracker& currentTracker(); + void setCurrentTracker(ITracker* tracker); + }; -bool completedCycle() const; -ITracker& currentTracker(); -void setCurrentTracker( ITracker* tracker ); -}; + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; -class TrackerBase : public ITracker { -protected: -enum CycleState { -NotStarted, -Executing, -ExecutingChildren, -NeedsAnotherRun, -CompletedSuccessfully, -Failed -}; + using Children = std::vector; + NameAndLocation m_nameAndLocation; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState = NotStarted; -using Children = std::vector; -NameAndLocation m_nameAndLocation; -TrackerContext& m_ctx; -ITracker* m_parent; -Children m_children; -CycleState m_runState = NotStarted; + public: + TrackerBase(NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent); -public: -TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + NameAndLocation const& nameAndLocation() const override; + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; -NameAndLocation const& nameAndLocation() const override; -bool isComplete() const override; -bool isSuccessfullyCompleted() const override; -bool isOpen() const override; -bool hasChildren() const override; + void addChild(ITrackerPtr const& child) override; -void addChild( ITrackerPtr const& child ) override; + ITrackerPtr findChild(NameAndLocation const& nameAndLocation) override; + ITracker& parent() override; -ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; -ITracker& parent() override; + void openChild() override; -void openChild() override; + bool isSectionTracker() const override; + bool isGeneratorTracker() const override; -bool isSectionTracker() const override; -bool isGeneratorTracker() const override; + void open(); -void open(); + void close() override; + void fail() override; + void markAsNeedingAnotherRun() override; -void close() override; -void fail() override; -void markAsNeedingAnotherRun() override; + private: + void moveToParent(); + void moveToThis(); + }; -private: -void moveToParent(); -void moveToThis(); -}; + class SectionTracker : public TrackerBase { + std::vector m_filters; + std::string m_trimmed_name; -class SectionTracker : public TrackerBase { -std::vector m_filters; -std::string m_trimmed_name; -public: -SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + public: + SectionTracker(NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent); -bool isSectionTracker() const override; + bool isSectionTracker() const override; -bool isComplete() const override; + bool isComplete() const override; -static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + static SectionTracker& acquire(TrackerContext& ctx, NameAndLocation const& nameAndLocation); -void tryOpen(); + void tryOpen(); -void addInitialFilters( std::vector const& filters ); -void addNextFilters( std::vector const& filters ); -}; + void addInitialFilters(std::vector const& filters); + void addNextFilters(std::vector const& filters); + }; -} // namespace TestCaseTracking + } // namespace TestCaseTracking -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; + using TestCaseTracking::ITracker; + using TestCaseTracking::SectionTracker; + using TestCaseTracking::TrackerContext; } // namespace Catch @@ -7544,10 +7466,10 @@ using TestCaseTracking::SectionTracker; namespace Catch { -struct LeakDetector { -LeakDetector(); -~LeakDetector(); -}; + struct LeakDetector { + LeakDetector(); + ~LeakDetector(); + }; } // end catch_leak_detector.h @@ -7566,199 +7488,203 @@ LeakDetector(); #endif namespace { -double erf_inv(double x) { -// Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 -double w, p; + double erf_inv(double x) { + // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 + double w, p; -w = -log((1.0 - x) * (1.0 + x)); + w = -log((1.0 - x) * (1.0 + x)); -if (w < 6.250000) { -w = w - 3.125000; -p = -3.6444120640178196996e-21; -p = -1.685059138182016589e-19 + p * w; -p = 1.2858480715256400167e-18 + p * w; -p = 1.115787767802518096e-17 + p * w; -p = -1.333171662854620906e-16 + p * w; -p = 2.0972767875968561637e-17 + p * w; -p = 6.6376381343583238325e-15 + p * w; -p = -4.0545662729752068639e-14 + p * w; -p = -8.1519341976054721522e-14 + p * w; -p = 2.6335093153082322977e-12 + p * w; -p = -1.2975133253453532498e-11 + p * w; -p = -5.4154120542946279317e-11 + p * w; -p = 1.051212273321532285e-09 + p * w; -p = -4.1126339803469836976e-09 + p * w; -p = -2.9070369957882005086e-08 + p * w; -p = 4.2347877827932403518e-07 + p * w; -p = -1.3654692000834678645e-06 + p * w; -p = -1.3882523362786468719e-05 + p * w; -p = 0.0001867342080340571352 + p * w; -p = -0.00074070253416626697512 + p * w; -p = -0.0060336708714301490533 + p * w; -p = 0.24015818242558961693 + p * w; -p = 1.6536545626831027356 + p * w; -} else if (w < 16.000000) { -w = sqrt(w) - 3.250000; -p = 2.2137376921775787049e-09; -p = 9.0756561938885390979e-08 + p * w; -p = -2.7517406297064545428e-07 + p * w; -p = 1.8239629214389227755e-08 + p * w; -p = 1.5027403968909827627e-06 + p * w; -p = -4.013867526981545969e-06 + p * w; -p = 2.9234449089955446044e-06 + p * w; -p = 1.2475304481671778723e-05 + p * w; -p = -4.7318229009055733981e-05 + p * w; -p = 6.8284851459573175448e-05 + p * w; -p = 2.4031110387097893999e-05 + p * w; -p = -0.0003550375203628474796 + p * w; -p = 0.00095328937973738049703 + p * w; -p = -0.0016882755560235047313 + p * w; -p = 0.0024914420961078508066 + p * w; -p = -0.0037512085075692412107 + p * w; -p = 0.005370914553590063617 + p * w; -p = 1.0052589676941592334 + p * w; -p = 3.0838856104922207635 + p * w; -} else { -w = sqrt(w) - 5.000000; -p = -2.7109920616438573243e-11; -p = -2.5556418169965252055e-10 + p * w; -p = 1.5076572693500548083e-09 + p * w; -p = -3.7894654401267369937e-09 + p * w; -p = 7.6157012080783393804e-09 + p * w; -p = -1.4960026627149240478e-08 + p * w; -p = 2.9147953450901080826e-08 + p * w; -p = -6.7711997758452339498e-08 + p * w; -p = 2.2900482228026654717e-07 + p * w; -p = -9.9298272942317002539e-07 + p * w; -p = 4.5260625972231537039e-06 + p * w; -p = -1.9681778105531670567e-05 + p * w; -p = 7.5995277030017761139e-05 + p * w; -p = -0.00021503011930044477347 + p * w; -p = -0.00013871931833623122026 + p * w; -p = 1.0103004648645343977 + p * w; -p = 4.8499064014085844221 + p * w; -} -return p * x; -} + if (w < 6.250000) { + w = w - 3.125000; + p = -3.6444120640178196996e-21; + p = -1.685059138182016589e-19 + p * w; + p = 1.2858480715256400167e-18 + p * w; + p = 1.115787767802518096e-17 + p * w; + p = -1.333171662854620906e-16 + p * w; + p = 2.0972767875968561637e-17 + p * w; + p = 6.6376381343583238325e-15 + p * w; + p = -4.0545662729752068639e-14 + p * w; + p = -8.1519341976054721522e-14 + p * w; + p = 2.6335093153082322977e-12 + p * w; + p = -1.2975133253453532498e-11 + p * w; + p = -5.4154120542946279317e-11 + p * w; + p = 1.051212273321532285e-09 + p * w; + p = -4.1126339803469836976e-09 + p * w; + p = -2.9070369957882005086e-08 + p * w; + p = 4.2347877827932403518e-07 + p * w; + p = -1.3654692000834678645e-06 + p * w; + p = -1.3882523362786468719e-05 + p * w; + p = 0.0001867342080340571352 + p * w; + p = -0.00074070253416626697512 + p * w; + p = -0.0060336708714301490533 + p * w; + p = 0.24015818242558961693 + p * w; + p = 1.6536545626831027356 + p * w; + } else if (w < 16.000000) { + w = sqrt(w) - 3.250000; + p = 2.2137376921775787049e-09; + p = 9.0756561938885390979e-08 + p * w; + p = -2.7517406297064545428e-07 + p * w; + p = 1.8239629214389227755e-08 + p * w; + p = 1.5027403968909827627e-06 + p * w; + p = -4.013867526981545969e-06 + p * w; + p = 2.9234449089955446044e-06 + p * w; + p = 1.2475304481671778723e-05 + p * w; + p = -4.7318229009055733981e-05 + p * w; + p = 6.8284851459573175448e-05 + p * w; + p = 2.4031110387097893999e-05 + p * w; + p = -0.0003550375203628474796 + p * w; + p = 0.00095328937973738049703 + p * w; + p = -0.0016882755560235047313 + p * w; + p = 0.0024914420961078508066 + p * w; + p = -0.0037512085075692412107 + p * w; + p = 0.005370914553590063617 + p * w; + p = 1.0052589676941592334 + p * w; + p = 3.0838856104922207635 + p * w; + } else { + w = sqrt(w) - 5.000000; + p = -2.7109920616438573243e-11; + p = -2.5556418169965252055e-10 + p * w; + p = 1.5076572693500548083e-09 + p * w; + p = -3.7894654401267369937e-09 + p * w; + p = 7.6157012080783393804e-09 + p * w; + p = -1.4960026627149240478e-08 + p * w; + p = 2.9147953450901080826e-08 + p * w; + p = -6.7711997758452339498e-08 + p * w; + p = 2.2900482228026654717e-07 + p * w; + p = -9.9298272942317002539e-07 + p * w; + p = 4.5260625972231537039e-06 + p * w; + p = -1.9681778105531670567e-05 + p * w; + p = 7.5995277030017761139e-05 + p * w; + p = -0.00021503011930044477347 + p * w; + p = -0.00013871931833623122026 + p * w; + p = 1.0103004648645343977 + p * w; + p = 4.8499064014085844221 + p * w; + } + return p * x; + } -double standard_deviation(std::vector::iterator first, std::vector::iterator last) { -auto m = Catch::Benchmark::Detail::mean(first, last); -double variance = std::accumulate(first, last, 0., [m](double a, double b) { -double diff = b - m; -return a + diff * diff; -}) / (last - first); -return std::sqrt(variance); -} + double standard_deviation(std::vector::iterator first, std::vector::iterator last) { + auto m = Catch::Benchmark::Detail::mean(first, last); + double variance = std::accumulate(first, last, 0., + [m](double a, double b) { + double diff = b - m; + return a + diff * diff; + }) / + (last - first); + return std::sqrt(variance); + } } namespace Catch { -namespace Benchmark { -namespace Detail { + namespace Benchmark { + namespace Detail { -double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last) { -auto count = last - first; -double idx = (count - 1) * k / static_cast(q); -int j = static_cast(idx); -double g = idx - j; -std::nth_element(first, first + j, last); -auto xj = first[j]; -if (g == 0) return xj; + double weighted_average_quantile(int k, int q, std::vector::iterator first, + std::vector::iterator last) { + auto count = last - first; + double idx = (count - 1) * k / static_cast(q); + int j = static_cast(idx); + double g = idx - j; + std::nth_element(first, first + j, last); + auto xj = first[j]; + if (g == 0) + return xj; -auto xj1 = *std::min_element(first + (j + 1), last); -return xj + g * (xj1 - xj); -} + auto xj1 = *std::min_element(first + (j + 1), last); + return xj + g * (xj1 - xj); + } -double erfc_inv(double x) { -return erf_inv(1.0 - x); -} + double erfc_inv(double x) { return erf_inv(1.0 - x); } -double normal_quantile(double p) { -static const double ROOT_TWO = std::sqrt(2.0); + double normal_quantile(double p) { + static const double ROOT_TWO = std::sqrt(2.0); -double result = 0.0; -assert(p >= 0 && p <= 1); -if (p < 0 || p > 1) { -return result; -} + double result = 0.0; + assert(p >= 0 && p <= 1); + if (p < 0 || p > 1) { + return result; + } -result = -erfc_inv(2.0 * p); -// result *= normal distribution standard deviation (1.0) * sqrt(2) -result *= /*sd * */ ROOT_TWO; -// result += normal disttribution mean (0) -return result; -} + result = -erfc_inv(2.0 * p); + // result *= normal distribution standard deviation (1.0) * sqrt(2) + result *= /*sd * */ ROOT_TWO; + // result += normal disttribution mean (0) + return result; + } -double outlier_variance(Estimate mean, Estimate stddev, int n) { -double sb = stddev.point; -double mn = mean.point / n; -double mg_min = mn / 2.; -double sg = std::min(mg_min / 4., sb / std::sqrt(n)); -double sg2 = sg * sg; -double sb2 = sb * sb; + double outlier_variance(Estimate mean, Estimate stddev, int n) { + double sb = stddev.point; + double mn = mean.point / n; + double mg_min = mn / 2.; + double sg = std::min(mg_min / 4., sb / std::sqrt(n)); + double sg2 = sg * sg; + double sb2 = sb * sb; -auto c_max = [n, mn, sb2, sg2](double x) -> double { -double k = mn - x; -double d = k * k; -double nd = n * d; -double k0 = -n * nd; -double k1 = sb2 - n * sg2 + nd; -double det = k1 * k1 - 4 * sg2 * k0; -return (int)(-2. * k0 / (k1 + std::sqrt(det))); -}; + auto c_max = [n, mn, sb2, sg2](double x) -> double { + double k = mn - x; + double d = k * k; + double nd = n * d; + double k0 = -n * nd; + double k1 = sb2 - n * sg2 + nd; + double det = k1 * k1 - 4 * sg2 * k0; + return (int)(-2. * k0 / (k1 + std::sqrt(det))); + }; -auto var_out = [n, sb2, sg2](double c) { -double nc = n - c; -return (nc / n) * (sb2 - nc * sg2); -}; + auto var_out = [n, sb2, sg2](double c) { + double nc = n - c; + return (nc / n) * (sb2 - nc * sg2); + }; -return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2; -} + return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2; + } -bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector::iterator first, std::vector::iterator last) { -CATCH_INTERNAL_START_WARNINGS_SUPPRESSION -CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -static std::random_device entropy; -CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, + std::vector::iterator first, + std::vector::iterator last) { + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS + static std::random_device entropy; + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -auto n = static_cast(last - first); // seriously, one can't use integral types without hell in C++ + auto n = static_cast(last - first); // seriously, one can't use integral types without hell in C++ -auto mean = &Detail::mean::iterator>; -auto stddev = &standard_deviation; + auto mean = &Detail::mean::iterator>; + auto stddev = &standard_deviation; #if defined(CATCH_CONFIG_USE_ASYNC) -auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { -auto seed = entropy(); -return std::async(std::launch::async, [=] { -std::mt19937 rng(seed); -auto resampled = resample(rng, n_resamples, first, last, f); -return bootstrap(confidence_level, first, last, resampled, f); -}); -}; + auto Estimate = [=](double (*f)(std::vector::iterator, std::vector::iterator)) { + auto seed = entropy(); + return std::async(std::launch::async, [=] { + std::mt19937 rng(seed); + auto resampled = resample(rng, n_resamples, first, last, f); + return bootstrap(confidence_level, first, last, resampled, f); + }); + }; -auto mean_future = Estimate(mean); -auto stddev_future = Estimate(stddev); + auto mean_future = Estimate(mean); + auto stddev_future = Estimate(stddev); -auto mean_estimate = mean_future.get(); -auto stddev_estimate = stddev_future.get(); + auto mean_estimate = mean_future.get(); + auto stddev_estimate = stddev_future.get(); #else -auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { -auto seed = entropy(); -std::mt19937 rng(seed); -auto resampled = resample(rng, n_resamples, first, last, f); -return bootstrap(confidence_level, first, last, resampled, f); -}; + auto Estimate = [=](double (*f)(std::vector::iterator, std::vector::iterator)) { + auto seed = entropy(); + std::mt19937 rng(seed); + auto resampled = resample(rng, n_resamples, first, last, f); + return bootstrap(confidence_level, first, last, resampled, f); + }; -auto mean_estimate = Estimate(mean); -auto stddev_estimate = Estimate(stddev); + auto mean_estimate = Estimate(mean); + auto stddev_estimate = Estimate(stddev); #endif // CATCH_USE_ASYNC -double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); + double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); -return { mean_estimate, stddev_estimate, outlier_variance }; -} -} // namespace Detail -} // namespace Benchmark + return {mean_estimate, stddev_estimate, outlier_variance}; + } + } // namespace Detail + } // namespace Benchmark } // namespace Catch #endif // CATCH_CONFIG_ENABLE_BENCHMARKING @@ -7770,75 +7696,64 @@ return { mean_estimate, stddev_estimate, outlier_variance }; namespace { -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { -return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); + } } namespace Catch { -namespace Detail { + namespace Detail { -Approx::Approx ( double value ) -: m_epsilon( std::numeric_limits::epsilon()*100 ), -m_margin( 0.0 ), -m_scale( 0.0 ), -m_value( value ) -{} + Approx::Approx(double value) + : m_epsilon(std::numeric_limits::epsilon() * 100), m_margin(0.0), m_scale(0.0), m_value(value) {} -Approx Approx::custom() { -return Approx( 0 ); -} + Approx Approx::custom() { return Approx(0); } -Approx Approx::operator-() const { -auto temp(*this); -temp.m_value = -temp.m_value; -return temp; -} + Approx Approx::operator-() const { + auto temp(*this); + temp.m_value = -temp.m_value; + return temp; + } -std::string Approx::toString() const { -ReusableStringStream rss; -rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; -return rss.str(); -} + std::string Approx::toString() const { + ReusableStringStream rss; + rss << "Approx( " << ::Catch::Detail::stringify(m_value) << " )"; + return rss.str(); + } -bool Approx::equalityComparisonImpl(const double other) const { -// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value -// Thanks to Richard Harris for his help refining the scaled margin value -return marginComparison(m_value, other, m_margin) -|| marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value))); -} + bool Approx::equalityComparisonImpl(const double other) const { + // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value + // Thanks to Richard Harris for his help refining the scaled margin value + return marginComparison(m_value, other, m_margin) || + marginComparison(m_value, other, + m_epsilon * (m_scale + std::fabs(std::isinf(m_value) ? 0 : m_value))); + } -void Approx::setMargin(double newMargin) { -CATCH_ENFORCE(newMargin >= 0, -"Invalid Approx::margin: " << newMargin << '.' -<< " Approx::Margin has to be non-negative."); -m_margin = newMargin; -} + void Approx::setMargin(double newMargin) { + CATCH_ENFORCE(newMargin >= 0, + "Invalid Approx::margin: " << newMargin << '.' << " Approx::Margin has to be non-negative."); + m_margin = newMargin; + } -void Approx::setEpsilon(double newEpsilon) { -CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, -"Invalid Approx::epsilon: " << newEpsilon << '.' -<< " Approx::epsilon has to be in [0, 1]"); -m_epsilon = newEpsilon; -} + void Approx::setEpsilon(double newEpsilon) { + CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, + "Invalid Approx::epsilon: " << newEpsilon << '.' << " Approx::epsilon has to be in [0, 1]"); + m_epsilon = newEpsilon; + } -} // end namespace Detail + } // end namespace Detail -namespace literals { -Detail::Approx operator "" _a(long double val) { -return Detail::Approx(val); -} -Detail::Approx operator "" _a(unsigned long long val) { -return Detail::Approx(val); -} -} // end namespace literals + namespace literals { + Detail::Approx operator"" _a(long double val) { return Detail::Approx(val); } + Detail::Approx operator"" _a(unsigned long long val) { return Detail::Approx(val); } + } // end namespace literals -std::string StringMaker::convert(Catch::Detail::Approx const& value) { -return value.toString(); -} + std::string StringMaker::convert(Catch::Detail::Approx const& value) { + return value.toString(); + } } // end namespace Catch // end catch_approx.cpp @@ -7847,20 +7762,20 @@ return value.toString(); // start catch_debugger.h namespace Catch { -bool isDebuggerActive(); + bool isDebuggerActive(); } #ifdef CATCH_PLATFORM_MAC -#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ +#define CATCH_TRAP() __asm__("int $3\n" : :) /* NOLINT */ #elif defined(CATCH_PLATFORM_LINUX) // If we can use inline assembler, do it because this allows us to break // directly at the location of the failing check instead of breaking inside // raise() called from it, i.e. one stack frame below. #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) -#define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ -#else // Fall back to the generic way. +#define CATCH_TRAP() asm volatile("int $3") /* NOLINT */ +#else // Fall back to the generic way. #include #define CATCH_TRAP() raise(SIGTRAP) @@ -7873,9 +7788,14 @@ extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #endif #ifdef CATCH_TRAP -#define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() +#define CATCH_BREAK_INTO_DEBUGGER() \ + [] { \ + if (Catch::isDebuggerActive()) { \ + CATCH_TRAP(); \ + } \ + }() #else -#define CATCH_BREAK_INTO_DEBUGGER() []{}() +#define CATCH_BREAK_INTO_DEBUGGER() [] {}() #endif // end catch_debugger.h @@ -7885,16 +7805,15 @@ extern "C" __declspec(dllimport) void __stdcall DebugBreak(); // start catch_windows_h_proxy.h - #if defined(CATCH_PLATFORM_WINDOWS) #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX -# define NOMINMAX +#define CATCH_DEFINED_NOMINMAX +#define NOMINMAX #endif #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN +#define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #endif #ifdef __AFXDLL @@ -7904,62 +7823,62 @@ extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #endif #ifdef CATCH_DEFINED_NOMINMAX -# undef NOMINMAX +#undef NOMINMAX #endif #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN #endif #endif // defined(CATCH_PLATFORM_WINDOWS) // end catch_windows_h_proxy.h -#if defined( CATCH_CONFIG_WINDOWS_SEH ) +#if defined(CATCH_CONFIG_WINDOWS_SEH) namespace Catch { -struct FatalConditionHandler { + struct FatalConditionHandler { -static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); -FatalConditionHandler(); -static void reset(); -~FatalConditionHandler(); + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + FatalConditionHandler(); + static void reset(); + ~FatalConditionHandler(); -private: -static bool isSet; -static ULONG guaranteeSize; -static PVOID exceptionHandlerHandle; -}; + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; } // namespace Catch -#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) +#elif defined(CATCH_CONFIG_POSIX_SIGNALS) #include namespace Catch { -struct FatalConditionHandler { + struct FatalConditionHandler { -static bool isSet; -static struct sigaction oldSigActions[]; -static stack_t oldSigStack; -static char altStackMem[]; + static bool isSet; + static struct sigaction oldSigActions[]; + static stack_t oldSigStack; + static char altStackMem[]; -static void handleSignal( int sig ); + static void handleSignal(int sig); -FatalConditionHandler(); -~FatalConditionHandler(); -static void reset(); -}; + FatalConditionHandler(); + ~FatalConditionHandler(); + static void reset(); + }; } // namespace Catch #else namespace Catch { -struct FatalConditionHandler { -void reset(); -}; + struct FatalConditionHandler { + void reset(); + }; } #endif @@ -7969,333 +7888,286 @@ void reset(); namespace Catch { -struct IMutableContext; + struct IMutableContext; -/////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// -class RunContext : public IResultCapture, public IRunner { + class RunContext : public IResultCapture, public IRunner { -public: -RunContext( RunContext const& ) = delete; -RunContext& operator =( RunContext const& ) = delete; + public: + RunContext(RunContext const&) = delete; + RunContext& operator=(RunContext const&) = delete; -explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); + explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter); -~RunContext() override; + ~RunContext() override; -void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); -void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); + void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount); + void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, + std::size_t groupsCount); -Totals runTest(TestCase const& testCase); + Totals runTest(TestCase const& testCase); -IConfigPtr config() const; -IStreamingReporter& reporter() const; + IConfigPtr config() const; + IStreamingReporter& reporter() const; -public: // IResultCapture + public: // IResultCapture + // Assertion handlers + void handleExpr(AssertionInfo const& info, ITransientExpression const& expr, + AssertionReaction& reaction) override; + void handleMessage(AssertionInfo const& info, ResultWas::OfType resultType, StringRef const& message, + AssertionReaction& reaction) override; + void handleUnexpectedExceptionNotThrown(AssertionInfo const& info, AssertionReaction& reaction) override; + void handleUnexpectedInflightException(AssertionInfo const& info, std::string const& message, + AssertionReaction& reaction) override; + void handleIncomplete(AssertionInfo const& info) override; + void handleNonExpr(AssertionInfo const& info, ResultWas::OfType resultType, + AssertionReaction& reaction) override; -// Assertion handlers -void handleExpr -( AssertionInfo const& info, -ITransientExpression const& expr, -AssertionReaction& reaction ) override; -void handleMessage -( AssertionInfo const& info, -ResultWas::OfType resultType, -StringRef const& message, -AssertionReaction& reaction ) override; -void handleUnexpectedExceptionNotThrown -( AssertionInfo const& info, -AssertionReaction& reaction ) override; -void handleUnexpectedInflightException -( AssertionInfo const& info, -std::string const& message, -AssertionReaction& reaction ) override; -void handleIncomplete -( AssertionInfo const& info ) override; -void handleNonExpr -( AssertionInfo const &info, -ResultWas::OfType resultType, -AssertionReaction &reaction ) override; + bool sectionStarted(SectionInfo const& sectionInfo, Counts& assertions) override; -bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + void sectionEnded(SectionEndInfo const& endInfo) override; + void sectionEndedEarly(SectionEndInfo const& endInfo) override; -void sectionEnded( SectionEndInfo const& endInfo ) override; -void sectionEndedEarly( SectionEndInfo const& endInfo ) override; - -auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + auto acquireGeneratorTracker(SourceLineInfo const& lineInfo) -> IGeneratorTracker& override; #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -void benchmarkPreparing( std::string const& name ) override; -void benchmarkStarting( BenchmarkInfo const& info ) override; -void benchmarkEnded( BenchmarkStats<> const& stats ) override; -void benchmarkFailed( std::string const& error ) override; + void benchmarkPreparing(std::string const& name) override; + void benchmarkStarting(BenchmarkInfo const& info) override; + void benchmarkEnded(BenchmarkStats<> const& stats) override; + void benchmarkFailed(std::string const& error) override; #endif // CATCH_CONFIG_ENABLE_BENCHMARKING -void pushScopedMessage( MessageInfo const& message ) override; -void popScopedMessage( MessageInfo const& message ) override; + void pushScopedMessage(MessageInfo const& message) override; + void popScopedMessage(MessageInfo const& message) override; -void emplaceUnscopedMessage( MessageBuilder const& builder ) override; + void emplaceUnscopedMessage(MessageBuilder const& builder) override; -std::string getCurrentTestName() const override; + std::string getCurrentTestName() const override; -const AssertionResult* getLastResult() const override; + const AssertionResult* getLastResult() const override; -void exceptionEarlyReported() override; + void exceptionEarlyReported() override; -void handleFatalErrorCondition( StringRef message ) override; + void handleFatalErrorCondition(StringRef message) override; -bool lastAssertionPassed() override; + bool lastAssertionPassed() override; -void assertionPassed() override; + void assertionPassed() override; -public: -// !TBD We need to do this another way! -bool aborting() const final; + public: + // !TBD We need to do this another way! + bool aborting() const final; -private: + private: + void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); + void invokeActiveTestCase(); -void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); -void invokeActiveTestCase(); + void resetAssertionInfo(); + bool testForMissingAssertions(Counts& assertions); -void resetAssertionInfo(); -bool testForMissingAssertions( Counts& assertions ); + void assertionEnded(AssertionResult const& result); + void reportExpr(AssertionInfo const& info, ResultWas::OfType resultType, ITransientExpression const* expr, + bool negated); -void assertionEnded( AssertionResult const& result ); -void reportExpr -( AssertionInfo const &info, -ResultWas::OfType resultType, -ITransientExpression const *expr, -bool negated ); + void populateReaction(AssertionReaction& reaction); -void populateReaction( AssertionReaction& reaction ); + private: + void handleUnfinishedSections(); -private: + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase = nullptr; + ITracker* m_testCaseTracker = nullptr; + Option m_lastResult; -void handleUnfinishedSections(); + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector m_messages; + std::vector m_messageScopes; /* Keeps owners of so-called unscoped messages. */ + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; + }; -TestRunInfo m_runInfo; -IMutableContext& m_context; -TestCase const* m_activeTestCase = nullptr; -ITracker* m_testCaseTracker = nullptr; -Option m_lastResult; - -IConfigPtr m_config; -Totals m_totals; -IStreamingReporterPtr m_reporter; -std::vector m_messages; -std::vector m_messageScopes; /* Keeps owners of so-called unscoped messages. */ -AssertionInfo m_lastAssertionInfo; -std::vector m_unfinishedSections; -std::vector m_activeSections; -TrackerContext m_trackerContext; -bool m_lastAssertionPassed = false; -bool m_shouldReportUnexpected = true; -bool m_includeSuccessfulResults; -}; - -void seedRng(IConfig const& config); -unsigned int rngSeed(); + void seedRng(IConfig const& config); + unsigned int rngSeed(); } // end namespace Catch // end catch_run_context.h namespace Catch { -namespace { -auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { -expr.streamReconstructedExpression( os ); -return os; -} -} + namespace { + auto operator<<(std::ostream& os, ITransientExpression const& expr) -> std::ostream& { + expr.streamReconstructedExpression(os); + return os; + } + } -LazyExpression::LazyExpression( bool isNegated ) -: m_isNegated( isNegated ) -{} + LazyExpression::LazyExpression(bool isNegated) : m_isNegated(isNegated) {} -LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + LazyExpression::LazyExpression(LazyExpression const& other) : m_isNegated(other.m_isNegated) {} -LazyExpression::operator bool() const { -return m_transientExpression != nullptr; -} + LazyExpression::operator bool() const { return m_transientExpression != nullptr; } -auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { -if( lazyExpr.m_isNegated ) -os << "!"; + auto operator<<(std::ostream& os, LazyExpression const& lazyExpr) -> std::ostream& { + if (lazyExpr.m_isNegated) + os << "!"; -if( lazyExpr ) { -if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) -os << "(" << *lazyExpr.m_transientExpression << ")"; -else -os << *lazyExpr.m_transientExpression; -} -else { -os << "{** error - unchecked empty expression requested **}"; -} -return os; -} + if (lazyExpr) { + if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression()) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } -AssertionHandler::AssertionHandler -( StringRef const& macroName, -SourceLineInfo const& lineInfo, -StringRef capturedExpression, -ResultDisposition::Flags resultDisposition ) -: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, -m_resultCapture( getResultCapture() ) -{} + AssertionHandler::AssertionHandler(StringRef const& macroName, SourceLineInfo const& lineInfo, + StringRef capturedExpression, ResultDisposition::Flags resultDisposition) + : m_assertionInfo{macroName, lineInfo, capturedExpression, resultDisposition}, + m_resultCapture(getResultCapture()) {} -void AssertionHandler::handleExpr( ITransientExpression const& expr ) { -m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); -} -void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { -m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); -} + void AssertionHandler::handleExpr(ITransientExpression const& expr) { + m_resultCapture.handleExpr(m_assertionInfo, expr, m_reaction); + } + void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { + m_resultCapture.handleMessage(m_assertionInfo, resultType, message, m_reaction); + } -auto AssertionHandler::allowThrows() const -> bool { -return getCurrentContext().getConfig()->allowThrows(); -} + auto AssertionHandler::allowThrows() const -> bool { return getCurrentContext().getConfig()->allowThrows(); } -void AssertionHandler::complete() { -setCompleted(); -if( m_reaction.shouldDebugBreak ) { + void AssertionHandler::complete() { + setCompleted(); + if (m_reaction.shouldDebugBreak) { -// If you find your debugger stopping you here then go one level up on the -// call-stack for the code that caused it (typically a failed assertion) + // If you find your debugger stopping you here then go one level up on the + // call-stack for the code that caused it (typically a failed assertion) -// (To go back to the test and change execution, jump over the throw, next) -CATCH_BREAK_INTO_DEBUGGER(); -} -if (m_reaction.shouldThrow) { + // (To go back to the test and change execution, jump over the throw, next) + CATCH_BREAK_INTO_DEBUGGER(); + } + if (m_reaction.shouldThrow) { #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -throw Catch::TestFailureException(); + throw Catch::TestFailureException(); #else -CATCH_ERROR( "Test failure requires aborting test!" ); + CATCH_ERROR("Test failure requires aborting test!"); #endif -} -} -void AssertionHandler::setCompleted() { -m_completed = true; -} + } + } + void AssertionHandler::setCompleted() { m_completed = true; } -void AssertionHandler::handleUnexpectedInflightException() { -m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); -} + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException(m_assertionInfo, Catch::translateActiveException(), + m_reaction); + } -void AssertionHandler::handleExceptionThrownAsExpected() { -m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); -} -void AssertionHandler::handleExceptionNotThrownAsExpected() { -m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); -} + void AssertionHandler::handleExceptionThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + void AssertionHandler::handleExceptionNotThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } -void AssertionHandler::handleUnexpectedExceptionNotThrown() { -m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); -} + void AssertionHandler::handleUnexpectedExceptionNotThrown() { + m_resultCapture.handleUnexpectedExceptionNotThrown(m_assertionInfo, m_reaction); + } -void AssertionHandler::handleThrowingCallSkipped() { -m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); -} + void AssertionHandler::handleThrowingCallSkipped() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } -// This is the overload that takes a string and infers the Equals matcher from it -// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp -void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { -handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); -} + // This is the overload that takes a string and infers the Equals matcher from it + // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp + void handleExceptionMatchExpr(AssertionHandler& handler, std::string const& str, StringRef const& matcherString) { + handleExceptionMatchExpr(handler, Matchers::Equals(str), matcherString); + } } // namespace Catch // end catch_assertionhandler.cpp // start catch_assertionresult.cpp namespace Catch { -AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): -lazyExpression(_lazyExpression), -resultType(_resultType) {} + AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const& _lazyExpression) + : lazyExpression(_lazyExpression), resultType(_resultType) {} -std::string AssertionResultData::reconstructExpression() const { + std::string AssertionResultData::reconstructExpression() const { -if( reconstructedExpression.empty() ) { -if( lazyExpression ) { -ReusableStringStream rss; -rss << lazyExpression; -reconstructedExpression = rss.str(); -} -} -return reconstructedExpression; -} + if (reconstructedExpression.empty()) { + if (lazyExpression) { + ReusableStringStream rss; + rss << lazyExpression; + reconstructedExpression = rss.str(); + } + } + return reconstructedExpression; + } -AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) -: m_info( info ), -m_resultData( data ) -{} + AssertionResult::AssertionResult(AssertionInfo const& info, AssertionResultData const& data) + : m_info(info), m_resultData(data) {} -// Result was a success -bool AssertionResult::succeeded() const { -return Catch::isOk( m_resultData.resultType ); -} + // Result was a success + bool AssertionResult::succeeded() const { return Catch::isOk(m_resultData.resultType); } -// Result was a success, or failure is suppressed -bool AssertionResult::isOk() const { -return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); -} + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk(m_resultData.resultType) || shouldSuppressFailure(m_info.resultDisposition); + } -ResultWas::OfType AssertionResult::getResultType() const { -return m_resultData.resultType; -} + ResultWas::OfType AssertionResult::getResultType() const { return m_resultData.resultType; } -bool AssertionResult::hasExpression() const { -return !m_info.capturedExpression.empty(); -} + bool AssertionResult::hasExpression() const { return !m_info.capturedExpression.empty(); } -bool AssertionResult::hasMessage() const { -return !m_resultData.message.empty(); -} + bool AssertionResult::hasMessage() const { return !m_resultData.message.empty(); } -std::string AssertionResult::getExpression() const { -// Possibly overallocating by 3 characters should be basically free -std::string expr; expr.reserve(m_info.capturedExpression.size() + 3); -if (isFalseTest(m_info.resultDisposition)) { -expr += "!("; -} -expr += m_info.capturedExpression; -if (isFalseTest(m_info.resultDisposition)) { -expr += ')'; -} -return expr; -} + std::string AssertionResult::getExpression() const { + // Possibly overallocating by 3 characters should be basically free + std::string expr; + expr.reserve(m_info.capturedExpression.size() + 3); + if (isFalseTest(m_info.resultDisposition)) { + expr += "!("; + } + expr += m_info.capturedExpression; + if (isFalseTest(m_info.resultDisposition)) { + expr += ')'; + } + return expr; + } -std::string AssertionResult::getExpressionInMacro() const { -std::string expr; -if( m_info.macroName.empty() ) -expr = static_cast(m_info.capturedExpression); -else { -expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); -expr += m_info.macroName; -expr += "( "; -expr += m_info.capturedExpression; -expr += " )"; -} -return expr; -} + std::string AssertionResult::getExpressionInMacro() const { + std::string expr; + if (m_info.macroName.empty()) + expr = static_cast(m_info.capturedExpression); + else { + expr.reserve(m_info.macroName.size() + m_info.capturedExpression.size() + 4); + expr += m_info.macroName; + expr += "( "; + expr += m_info.capturedExpression; + expr += " )"; + } + return expr; + } -bool AssertionResult::hasExpandedExpression() const { -return hasExpression() && getExpandedExpression() != getExpression(); -} + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } -std::string AssertionResult::getExpandedExpression() const { -std::string expr = m_resultData.reconstructExpression(); -return expr.empty() -? getExpression() -: expr; -} + std::string AssertionResult::getExpandedExpression() const { + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() ? getExpression() : expr; + } -std::string AssertionResult::getMessage() const { -return m_resultData.message; -} -SourceLineInfo AssertionResult::getSourceInfo() const { -return m_info.lineInfo; -} + std::string AssertionResult::getMessage() const { return m_resultData.message; } + SourceLineInfo AssertionResult::getSourceInfo() const { return m_info.lineInfo; } -StringRef AssertionResult::getTestMacroName() const { -return m_info.macroName; -} + StringRef AssertionResult::getTestMacroName() const { return m_info.macroName; } } // end namespace Catch // end catch_assertionresult.cpp @@ -8303,16 +8175,17 @@ return m_info.macroName; namespace Catch { -using StringMatcher = Matchers::Impl::MatcherBase; + using StringMatcher = Matchers::Impl::MatcherBase; -// This is the general overload that takes a any string matcher -// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers -// the Equals matcher (so the header does not mention matchers) -void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { -std::string exceptionMessage = Catch::translateActiveException(); -MatchExpr expr( exceptionMessage, matcher, matcherString ); -handler.handleExpr( expr ); -} + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + void handleExceptionMatchExpr(AssertionHandler& handler, StringMatcher const& matcher, + StringRef const& matcherString) { + std::string exceptionMessage = Catch::translateActiveException(); + MatchExpr expr(exceptionMessage, matcher, matcherString); + handler.handleExpr(expr); + } } // namespace Catch // end catch_capture_matchers.cpp @@ -8327,7 +8200,7 @@ handler.handleExpr( expr ); #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH #endif -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - 1 #ifdef __clang__ #pragma clang diagnostic push @@ -8346,7 +8219,6 @@ handler.handleExpr( expr ); // Clara v1.1.5 - #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 #endif @@ -8375,7 +8247,6 @@ handler.handleExpr( expr ); // // This project is hosted at https://github.com/philsquared/textflowcpp - #include #include #include @@ -8386,1210 +8257,1147 @@ handler.handleExpr( expr ); #endif namespace Catch { -namespace clara { -namespace TextFlow { + namespace clara { + namespace TextFlow { -inline auto isWhitespace(char c) -> bool { -static std::string chars = " \t\n\r"; -return chars.find(c) != std::string::npos; -} -inline auto isBreakableBefore(char c) -> bool { -static std::string chars = "[({<|"; -return chars.find(c) != std::string::npos; -} -inline auto isBreakableAfter(char c) -> bool { -static std::string chars = "])}>.,:;*+-=&/\\"; -return chars.find(c) != std::string::npos; -} + inline auto isWhitespace(char c) -> bool { + static std::string chars = " \t\n\r"; + return chars.find(c) != std::string::npos; + } + inline auto isBreakableBefore(char c) -> bool { + static std::string chars = "[({<|"; + return chars.find(c) != std::string::npos; + } + inline auto isBreakableAfter(char c) -> bool { + static std::string chars = "])}>.,:;*+-=&/\\"; + return chars.find(c) != std::string::npos; + } -class Columns; + class Columns; -class Column { -std::vector m_strings; -size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; -size_t m_indent = 0; -size_t m_initialIndent = std::string::npos; + class Column { + std::vector m_strings; + size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; -public: -class iterator { -friend Column; + public: + class iterator { + friend Column; -Column const& m_column; -size_t m_stringIndex = 0; -size_t m_pos = 0; + Column const& m_column; + size_t m_stringIndex = 0; + size_t m_pos = 0; -size_t m_len = 0; -size_t m_end = 0; -bool m_suffix = false; + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; -iterator(Column const& column, size_t stringIndex) -: m_column(column), -m_stringIndex(stringIndex) {} + iterator(Column const& column, size_t stringIndex) : m_column(column), m_stringIndex(stringIndex) {} -auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } + auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } -auto isBoundary(size_t at) const -> bool { -assert(at > 0); -assert(at <= line().size()); + auto isBoundary(size_t at) const -> bool { + assert(at > 0); + assert(at <= line().size()); -return at == line().size() || -(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || -isBreakableBefore(line()[at]) || -isBreakableAfter(line()[at - 1]); -} + return at == line().size() || (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || + isBreakableBefore(line()[at]) || isBreakableAfter(line()[at - 1]); + } -void calcLength() { -assert(m_stringIndex < m_column.m_strings.size()); + void calcLength() { + assert(m_stringIndex < m_column.m_strings.size()); -m_suffix = false; -auto width = m_column.m_width - indent(); -m_end = m_pos; -if (line()[m_pos] == '\n') { -++m_end; -} -while (m_end < line().size() && line()[m_end] != '\n') -++m_end; + m_suffix = false; + auto width = m_column.m_width - indent(); + m_end = m_pos; + if (line()[m_pos] == '\n') { + ++m_end; + } + while (m_end < line().size() && line()[m_end] != '\n') + ++m_end; -if (m_end < m_pos + width) { -m_len = m_end - m_pos; -} else { -size_t len = width; -while (len > 0 && !isBoundary(m_pos + len)) ---len; -while (len > 0 && isWhitespace(line()[m_pos + len - 1])) ---len; + if (m_end < m_pos + width) { + m_len = m_end - m_pos; + } else { + size_t len = width; + while (len > 0 && !isBoundary(m_pos + len)) + --len; + while (len > 0 && isWhitespace(line()[m_pos + len - 1])) + --len; -if (len > 0) { -m_len = len; -} else { -m_suffix = true; -m_len = width - 1; -} -} -} + if (len > 0) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } -auto indent() const -> size_t { -auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; -return initial == std::string::npos ? m_column.m_indent : initial; -} + auto indent() const -> size_t { + auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } -auto addIndentAndSuffix(std::string const &plain) const -> std::string { -return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); -} + auto addIndentAndSuffix(std::string const& plain) const -> std::string { + return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); + } -public: -using difference_type = std::ptrdiff_t; -using value_type = std::string; -using pointer = value_type * ; -using reference = value_type & ; -using iterator_category = std::forward_iterator_tag; + public: + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::forward_iterator_tag; -explicit iterator(Column const& column) : m_column(column) { -assert(m_column.m_width > m_column.m_indent); -assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent); -calcLength(); -if (m_len == 0) -m_stringIndex++; // Empty string -} + explicit iterator(Column const& column) : m_column(column) { + assert(m_column.m_width > m_column.m_indent); + assert(m_column.m_initialIndent == std::string::npos || + m_column.m_width > m_column.m_initialIndent); + calcLength(); + if (m_len == 0) + m_stringIndex++; // Empty string + } -auto operator *() const -> std::string { -assert(m_stringIndex < m_column.m_strings.size()); -assert(m_pos <= m_end); -return addIndentAndSuffix(line().substr(m_pos, m_len)); -} + auto operator*() const -> std::string { + assert(m_stringIndex < m_column.m_strings.size()); + assert(m_pos <= m_end); + return addIndentAndSuffix(line().substr(m_pos, m_len)); + } -auto operator ++() -> iterator& { -m_pos += m_len; -if (m_pos < line().size() && line()[m_pos] == '\n') -m_pos += 1; -else -while (m_pos < line().size() && isWhitespace(line()[m_pos])) -++m_pos; + auto operator++() -> iterator& { + m_pos += m_len; + if (m_pos < line().size() && line()[m_pos] == '\n') + m_pos += 1; + else + while (m_pos < line().size() && isWhitespace(line()[m_pos])) + ++m_pos; -if (m_pos == line().size()) { -m_pos = 0; -++m_stringIndex; -} -if (m_stringIndex < m_column.m_strings.size()) -calcLength(); -return *this; -} -auto operator ++(int) -> iterator { -iterator prev(*this); -operator++(); -return prev; -} + if (m_pos == line().size()) { + m_pos = 0; + ++m_stringIndex; + } + if (m_stringIndex < m_column.m_strings.size()) + calcLength(); + return *this; + } + auto operator++(int) -> iterator { + iterator prev(*this); + operator++(); + return prev; + } -auto operator ==(iterator const& other) const -> bool { -return -m_pos == other.m_pos && -m_stringIndex == other.m_stringIndex && -&m_column == &other.m_column; -} -auto operator !=(iterator const& other) const -> bool { -return !operator==(other); -} -}; -using const_iterator = iterator; + auto operator==(iterator const& other) const -> bool { + return m_pos == other.m_pos && m_stringIndex == other.m_stringIndex && + &m_column == &other.m_column; + } + auto operator!=(iterator const& other) const -> bool { return !operator==(other); } + }; + using const_iterator = iterator; -explicit Column(std::string const& text) { m_strings.push_back(text); } + explicit Column(std::string const& text) { m_strings.push_back(text); } -auto width(size_t newWidth) -> Column& { -assert(newWidth > 0); -m_width = newWidth; -return *this; -} -auto indent(size_t newIndent) -> Column& { -m_indent = newIndent; -return *this; -} -auto initialIndent(size_t newIndent) -> Column& { -m_initialIndent = newIndent; -return *this; -} + auto width(size_t newWidth) -> Column& { + assert(newWidth > 0); + m_width = newWidth; + return *this; + } + auto indent(size_t newIndent) -> Column& { + m_indent = newIndent; + return *this; + } + auto initialIndent(size_t newIndent) -> Column& { + m_initialIndent = newIndent; + return *this; + } -auto width() const -> size_t { return m_width; } -auto begin() const -> iterator { return iterator(*this); } -auto end() const -> iterator { return { *this, m_strings.size() }; } + auto width() const -> size_t { return m_width; } + auto begin() const -> iterator { return iterator(*this); } + auto end() const -> iterator { return {*this, m_strings.size()}; } -inline friend std::ostream& operator << (std::ostream& os, Column const& col) { -bool first = true; -for (auto line : col) { -if (first) -first = false; -else -os << "\n"; -os << line; -} -return os; -} + inline friend std::ostream& operator<<(std::ostream& os, Column const& col) { + bool first = true; + for (auto line : col) { + if (first) + first = false; + else + os << "\n"; + os << line; + } + return os; + } -auto operator + (Column const& other)->Columns; + auto operator+(Column const& other) -> Columns; -auto toString() const -> std::string { -std::ostringstream oss; -oss << *this; -return oss.str(); -} -}; + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; -class Spacer : public Column { + class Spacer : public Column { -public: -explicit Spacer(size_t spaceWidth) : Column("") { -width(spaceWidth); -} -}; + public: + explicit Spacer(size_t spaceWidth) : Column("") { width(spaceWidth); } + }; -class Columns { -std::vector m_columns; + class Columns { + std::vector m_columns; -public: + public: + class iterator { + friend Columns; + struct EndTag {}; -class iterator { -friend Columns; -struct EndTag {}; + std::vector const& m_columns; + std::vector m_iterators; + size_t m_activeIterators; -std::vector const& m_columns; -std::vector m_iterators; -size_t m_activeIterators; + iterator(Columns const& columns, EndTag) : m_columns(columns.m_columns), m_activeIterators(0) { + m_iterators.reserve(m_columns.size()); -iterator(Columns const& columns, EndTag) -: m_columns(columns.m_columns), -m_activeIterators(0) { -m_iterators.reserve(m_columns.size()); + for (auto const& col : m_columns) + m_iterators.push_back(col.end()); + } -for (auto const& col : m_columns) -m_iterators.push_back(col.end()); -} + public: + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::forward_iterator_tag; -public: -using difference_type = std::ptrdiff_t; -using value_type = std::string; -using pointer = value_type * ; -using reference = value_type & ; -using iterator_category = std::forward_iterator_tag; + explicit iterator(Columns const& columns) + : m_columns(columns.m_columns), m_activeIterators(m_columns.size()) { + m_iterators.reserve(m_columns.size()); -explicit iterator(Columns const& columns) -: m_columns(columns.m_columns), -m_activeIterators(m_columns.size()) { -m_iterators.reserve(m_columns.size()); + for (auto const& col : m_columns) + m_iterators.push_back(col.begin()); + } -for (auto const& col : m_columns) -m_iterators.push_back(col.begin()); -} + auto operator==(iterator const& other) const -> bool { return m_iterators == other.m_iterators; } + auto operator!=(iterator const& other) const -> bool { return m_iterators != other.m_iterators; } + auto operator*() const -> std::string { + std::string row, padding; -auto operator ==(iterator const& other) const -> bool { -return m_iterators == other.m_iterators; -} -auto operator !=(iterator const& other) const -> bool { -return m_iterators != other.m_iterators; -} -auto operator *() const -> std::string { -std::string row, padding; + for (size_t i = 0; i < m_columns.size(); ++i) { + auto width = m_columns[i].width(); + if (m_iterators[i] != m_columns[i].end()) { + std::string col = *m_iterators[i]; + row += padding + col; + if (col.size() < width) + padding = std::string(width - col.size(), ' '); + else + padding = ""; + } else { + padding += std::string(width, ' '); + } + } + return row; + } + auto operator++() -> iterator& { + for (size_t i = 0; i < m_columns.size(); ++i) { + if (m_iterators[i] != m_columns[i].end()) + ++m_iterators[i]; + } + return *this; + } + auto operator++(int) -> iterator { + iterator prev(*this); + operator++(); + return prev; + } + }; + using const_iterator = iterator; -for (size_t i = 0; i < m_columns.size(); ++i) { -auto width = m_columns[i].width(); -if (m_iterators[i] != m_columns[i].end()) { -std::string col = *m_iterators[i]; -row += padding + col; -if (col.size() < width) -padding = std::string(width - col.size(), ' '); -else -padding = ""; -} else { -padding += std::string(width, ' '); -} -} -return row; -} -auto operator ++() -> iterator& { -for (size_t i = 0; i < m_columns.size(); ++i) { -if (m_iterators[i] != m_columns[i].end()) -++m_iterators[i]; -} -return *this; -} -auto operator ++(int) -> iterator { -iterator prev(*this); -operator++(); -return prev; -} -}; -using const_iterator = iterator; + auto begin() const -> iterator { return iterator(*this); } + auto end() const -> iterator { return {*this, iterator::EndTag()}; } -auto begin() const -> iterator { return iterator(*this); } -auto end() const -> iterator { return { *this, iterator::EndTag() }; } + auto operator+=(Column const& col) -> Columns& { + m_columns.push_back(col); + return *this; + } + auto operator+(Column const& col) -> Columns { + Columns combined = *this; + combined += col; + return combined; + } -auto operator += (Column const& col) -> Columns& { -m_columns.push_back(col); -return *this; -} -auto operator + (Column const& col) -> Columns { -Columns combined = *this; -combined += col; -return combined; -} + inline friend std::ostream& operator<<(std::ostream& os, Columns const& cols) { -inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) { + bool first = true; + for (auto line : cols) { + if (first) + first = false; + else + os << "\n"; + os << line; + } + return os; + } -bool first = true; -for (auto line : cols) { -if (first) -first = false; -else -os << "\n"; -os << line; -} -return os; -} + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; -auto toString() const -> std::string { -std::ostringstream oss; -oss << *this; -return oss.str(); -} -}; + inline auto Column::operator+(Column const& other) -> Columns { + Columns cols; + cols += *this; + cols += other; + return cols; + } + } -inline auto Column::operator + (Column const& other) -> Columns { -Columns cols; -cols += *this; -cols += other; -return cols; -} -} - -} + } } // ----------- end of #include from clara_textflow.hpp ----------- // ........... back in clara.hpp +#include #include -#include #include #include -#include +#include -#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) +#if !defined(CATCH_PLATFORM_WINDOWS) && (defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)) #define CATCH_PLATFORM_WINDOWS #endif -namespace Catch { namespace clara { -namespace detail { +namespace Catch { + namespace clara { + namespace detail { -// Traits for extracting arg and return type of lambdas (for single argument lambdas) -template -struct UnaryLambdaTraits : UnaryLambdaTraits {}; + // Traits for extracting arg and return type of lambdas (for single argument lambdas) + template struct UnaryLambdaTraits : UnaryLambdaTraits {}; -template -struct UnaryLambdaTraits { -static const bool isValid = false; -}; + template + struct UnaryLambdaTraits { + static const bool isValid = false; + }; -template -struct UnaryLambdaTraits { -static const bool isValid = true; -using ArgType = typename std::remove_const::type>::type; -using ReturnType = ReturnT; -}; + template + struct UnaryLambdaTraits { + static const bool isValid = true; + using ArgType = typename std::remove_const::type>::type; + using ReturnType = ReturnT; + }; -class TokenStream; + class TokenStream; -// Transport for raw args (copied from main args, or supplied via init list for testing) -class Args { -friend TokenStream; -std::string m_exeName; -std::vector m_args; + // Transport for raw args (copied from main args, or supplied via init list for testing) + class Args { + friend TokenStream; + std::string m_exeName; + std::vector m_args; -public: -Args( int argc, char const* const* argv ) -: m_exeName(argv[0]), -m_args(argv + 1, argv + argc) {} + public: + Args(int argc, char const* const* argv) : m_exeName(argv[0]), m_args(argv + 1, argv + argc) {} -Args( std::initializer_list args ) -: m_exeName( *args.begin() ), -m_args( args.begin()+1, args.end() ) -{} + Args(std::initializer_list args) + : m_exeName(*args.begin()), m_args(args.begin() + 1, args.end()) {} -auto exeName() const -> std::string { -return m_exeName; -} -}; + auto exeName() const -> std::string { return m_exeName; } + }; -// Wraps a token coming from a token stream. These may not directly correspond to strings as a single string -// may encode an option + its argument if the : or = form is used -enum class TokenType { -Option, Argument -}; -struct Token { -TokenType type; -std::string token; -}; + // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string + // may encode an option + its argument if the : or = form is used + enum class TokenType { Option, Argument }; + struct Token { + TokenType type; + std::string token; + }; -inline auto isOptPrefix( char c ) -> bool { -return c == '-' + inline auto isOptPrefix(char c) -> bool { + return c == '-' #ifdef CATCH_PLATFORM_WINDOWS -|| c == '/' + || c == '/' #endif -; -} + ; + } -// Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled -class TokenStream { -using Iterator = std::vector::const_iterator; -Iterator it; -Iterator itEnd; -std::vector m_tokenBuffer; + // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled + class TokenStream { + using Iterator = std::vector::const_iterator; + Iterator it; + Iterator itEnd; + std::vector m_tokenBuffer; -void loadBuffer() { -m_tokenBuffer.resize( 0 ); + void loadBuffer() { + m_tokenBuffer.resize(0); -// Skip any empty strings -while( it != itEnd && it->empty() ) -++it; + // Skip any empty strings + while (it != itEnd && it->empty()) + ++it; -if( it != itEnd ) { -auto const &next = *it; -if( isOptPrefix( next[0] ) ) { -auto delimiterPos = next.find_first_of( " :=" ); -if( delimiterPos != std::string::npos ) { -m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); -m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); -} else { -if( next[1] != '-' && next.size() > 2 ) { -std::string opt = "- "; -for( size_t i = 1; i < next.size(); ++i ) { -opt[1] = next[i]; -m_tokenBuffer.push_back( { TokenType::Option, opt } ); -} -} else { -m_tokenBuffer.push_back( { TokenType::Option, next } ); -} -} -} else { -m_tokenBuffer.push_back( { TokenType::Argument, next } ); -} -} -} + if (it != itEnd) { + auto const& next = *it; + if (isOptPrefix(next[0])) { + auto delimiterPos = next.find_first_of(" :="); + if (delimiterPos != std::string::npos) { + m_tokenBuffer.push_back({TokenType::Option, next.substr(0, delimiterPos)}); + m_tokenBuffer.push_back({TokenType::Argument, next.substr(delimiterPos + 1)}); + } else { + if (next[1] != '-' && next.size() > 2) { + std::string opt = "- "; + for (size_t i = 1; i < next.size(); ++i) { + opt[1] = next[i]; + m_tokenBuffer.push_back({TokenType::Option, opt}); + } + } else { + m_tokenBuffer.push_back({TokenType::Option, next}); + } + } + } else { + m_tokenBuffer.push_back({TokenType::Argument, next}); + } + } + } -public: -explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} + public: + explicit TokenStream(Args const& args) : TokenStream(args.m_args.begin(), args.m_args.end()) {} -TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { -loadBuffer(); -} + TokenStream(Iterator it, Iterator itEnd) : it(it), itEnd(itEnd) { loadBuffer(); } -explicit operator bool() const { -return !m_tokenBuffer.empty() || it != itEnd; -} + explicit operator bool() const { return !m_tokenBuffer.empty() || it != itEnd; } -auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } -auto operator*() const -> Token { -assert( !m_tokenBuffer.empty() ); -return m_tokenBuffer.front(); -} + auto operator*() const -> Token { + assert(!m_tokenBuffer.empty()); + return m_tokenBuffer.front(); + } -auto operator->() const -> Token const * { -assert( !m_tokenBuffer.empty() ); -return &m_tokenBuffer.front(); -} + auto operator-> () const -> Token const* { + assert(!m_tokenBuffer.empty()); + return &m_tokenBuffer.front(); + } -auto operator++() -> TokenStream & { -if( m_tokenBuffer.size() >= 2 ) { -m_tokenBuffer.erase( m_tokenBuffer.begin() ); -} else { -if( it != itEnd ) -++it; -loadBuffer(); -} -return *this; -} -}; + auto operator++() -> TokenStream& { + if (m_tokenBuffer.size() >= 2) { + m_tokenBuffer.erase(m_tokenBuffer.begin()); + } else { + if (it != itEnd) + ++it; + loadBuffer(); + } + return *this; + } + }; -class ResultBase { -public: -enum Type { -Ok, LogicError, RuntimeError -}; + class ResultBase { + public: + enum Type { Ok, LogicError, RuntimeError }; -protected: -ResultBase( Type type ) : m_type( type ) {} -virtual ~ResultBase() = default; + protected: + ResultBase(Type type) : m_type(type) {} + virtual ~ResultBase() = default; -virtual void enforceOk() const = 0; + virtual void enforceOk() const = 0; -Type m_type; -}; + Type m_type; + }; -template -class ResultValueBase : public ResultBase { -public: -auto value() const -> T const & { -enforceOk(); -return m_value; -} + template class ResultValueBase : public ResultBase { + public: + auto value() const -> T const& { + enforceOk(); + return m_value; + } -protected: -ResultValueBase( Type type ) : ResultBase( type ) {} + protected: + ResultValueBase(Type type) : ResultBase(type) {} -ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { -if( m_type == ResultBase::Ok ) -new( &m_value ) T( other.m_value ); -} + ResultValueBase(ResultValueBase const& other) : ResultBase(other) { + if (m_type == ResultBase::Ok) + new (&m_value) T(other.m_value); + } -ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { -new( &m_value ) T( value ); -} + ResultValueBase(Type, T const& value) : ResultBase(Ok) { new (&m_value) T(value); } -auto operator=( ResultValueBase const &other ) -> ResultValueBase & { -if( m_type == ResultBase::Ok ) -m_value.~T(); -ResultBase::operator=(other); -if( m_type == ResultBase::Ok ) -new( &m_value ) T( other.m_value ); -return *this; -} + auto operator=(ResultValueBase const& other) -> ResultValueBase& { + if (m_type == ResultBase::Ok) + m_value.~T(); + ResultBase::operator=(other); + if (m_type == ResultBase::Ok) + new (&m_value) T(other.m_value); + return *this; + } -~ResultValueBase() override { -if( m_type == Ok ) -m_value.~T(); -} + ~ResultValueBase() override { + if (m_type == Ok) + m_value.~T(); + } -union { -T m_value; -}; -}; + union { + T m_value; + }; + }; -template<> -class ResultValueBase : public ResultBase { -protected: -using ResultBase::ResultBase; -}; + template <> class ResultValueBase : public ResultBase { + protected: + using ResultBase::ResultBase; + }; -template -class BasicResult : public ResultValueBase { -public: -template -explicit BasicResult( BasicResult const &other ) -: ResultValueBase( other.type() ), -m_errorMessage( other.errorMessage() ) -{ -assert( type() != ResultBase::Ok ); -} + template class BasicResult : public ResultValueBase { + public: + template + explicit BasicResult(BasicResult const& other) + : ResultValueBase(other.type()), m_errorMessage(other.errorMessage()) { + assert(type() != ResultBase::Ok); + } -template -static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } -static auto ok() -> BasicResult { return { ResultBase::Ok }; } -static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } -static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } + template static auto ok(U const& value) -> BasicResult { return {ResultBase::Ok, value}; } + static auto ok() -> BasicResult { return {ResultBase::Ok}; } + static auto logicError(std::string const& message) -> BasicResult { + return {ResultBase::LogicError, message}; + } + static auto runtimeError(std::string const& message) -> BasicResult { + return {ResultBase::RuntimeError, message}; + } -explicit operator bool() const { return m_type == ResultBase::Ok; } -auto type() const -> ResultBase::Type { return m_type; } -auto errorMessage() const -> std::string { return m_errorMessage; } + explicit operator bool() const { return m_type == ResultBase::Ok; } + auto type() const -> ResultBase::Type { return m_type; } + auto errorMessage() const -> std::string { return m_errorMessage; } -protected: -void enforceOk() const override { + protected: + void enforceOk() const override { -// Errors shouldn't reach this point, but if they do -// the actual error message will be in m_errorMessage -assert( m_type != ResultBase::LogicError ); -assert( m_type != ResultBase::RuntimeError ); -if( m_type != ResultBase::Ok ) -std::abort(); -} + // Errors shouldn't reach this point, but if they do + // the actual error message will be in m_errorMessage + assert(m_type != ResultBase::LogicError); + assert(m_type != ResultBase::RuntimeError); + if (m_type != ResultBase::Ok) + std::abort(); + } -std::string m_errorMessage; // Only populated if resultType is an error + std::string m_errorMessage; // Only populated if resultType is an error -BasicResult( ResultBase::Type type, std::string const &message ) -: ResultValueBase(type), -m_errorMessage(message) -{ -assert( m_type != ResultBase::Ok ); -} + BasicResult(ResultBase::Type type, std::string const& message) + : ResultValueBase(type), m_errorMessage(message) { + assert(m_type != ResultBase::Ok); + } -using ResultValueBase::ResultValueBase; -using ResultBase::m_type; -}; + using ResultValueBase::ResultValueBase; + using ResultBase::m_type; + }; -enum class ParseResultType { -Matched, NoMatch, ShortCircuitAll, ShortCircuitSame -}; + enum class ParseResultType { Matched, NoMatch, ShortCircuitAll, ShortCircuitSame }; -class ParseState { -public: + class ParseState { + public: + ParseState(ParseResultType type, TokenStream const& remainingTokens) + : m_type(type), m_remainingTokens(remainingTokens) {} -ParseState( ParseResultType type, TokenStream const &remainingTokens ) -: m_type(type), -m_remainingTokens( remainingTokens ) -{} + auto type() const -> ParseResultType { return m_type; } + auto remainingTokens() const -> TokenStream { return m_remainingTokens; } -auto type() const -> ParseResultType { return m_type; } -auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + private: + ParseResultType m_type; + TokenStream m_remainingTokens; + }; -private: -ParseResultType m_type; -TokenStream m_remainingTokens; -}; + using Result = BasicResult; + using ParserResult = BasicResult; + using InternalParseResult = BasicResult; -using Result = BasicResult; -using ParserResult = BasicResult; -using InternalParseResult = BasicResult; + struct HelpColumns { + std::string left; + std::string right; + }; -struct HelpColumns { -std::string left; -std::string right; -}; - -template -inline auto convertInto( std::string const &source, T& target ) -> ParserResult { -std::stringstream ss; -ss << source; -ss >> target; -if( ss.fail() ) -return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); -else -return ParserResult::ok( ParseResultType::Matched ); -} -inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { -target = source; -return ParserResult::ok( ParseResultType::Matched ); -} -inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { -std::string srcLC = source; -std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( std::tolower(c) ); } ); -if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") -target = true; -else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") -target = false; -else -return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); -return ParserResult::ok( ParseResultType::Matched ); -} + template inline auto convertInto(std::string const& source, T& target) -> ParserResult { + std::stringstream ss; + ss << source; + ss >> target; + if (ss.fail()) + return ParserResult::runtimeError("Unable to convert '" + source + "' to destination type"); + else + return ParserResult::ok(ParseResultType::Matched); + } + inline auto convertInto(std::string const& source, std::string& target) -> ParserResult { + target = source; + return ParserResult::ok(ParseResultType::Matched); + } + inline auto convertInto(std::string const& source, bool& target) -> ParserResult { + std::string srcLC = source; + std::transform(srcLC.begin(), srcLC.end(), srcLC.begin(), + [](char c) { return static_cast(std::tolower(c)); }); + if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") + target = true; + else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") + target = false; + else + return ParserResult::runtimeError("Expected a boolean value but did not recognise: '" + source + + "'"); + return ParserResult::ok(ParseResultType::Matched); + } #ifdef CLARA_CONFIG_OPTIONAL_TYPE -template -inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { -T temp; -auto result = convertInto( source, temp ); -if( result ) -target = std::move(temp); -return result; -} + template + inline auto convertInto(std::string const& source, CLARA_CONFIG_OPTIONAL_TYPE& target) -> ParserResult { + T temp; + auto result = convertInto(source, temp); + if (result) + target = std::move(temp); + return result; + } #endif // CLARA_CONFIG_OPTIONAL_TYPE -struct NonCopyable { -NonCopyable() = default; -NonCopyable( NonCopyable const & ) = delete; -NonCopyable( NonCopyable && ) = delete; -NonCopyable &operator=( NonCopyable const & ) = delete; -NonCopyable &operator=( NonCopyable && ) = delete; -}; + struct NonCopyable { + NonCopyable() = default; + NonCopyable(NonCopyable const&) = delete; + NonCopyable(NonCopyable&&) = delete; + NonCopyable& operator=(NonCopyable const&) = delete; + NonCopyable& operator=(NonCopyable&&) = delete; + }; -struct BoundRef : NonCopyable { -virtual ~BoundRef() = default; -virtual auto isContainer() const -> bool { return false; } -virtual auto isFlag() const -> bool { return false; } -}; -struct BoundValueRefBase : BoundRef { -virtual auto setValue( std::string const &arg ) -> ParserResult = 0; -}; -struct BoundFlagRefBase : BoundRef { -virtual auto setFlag( bool flag ) -> ParserResult = 0; -virtual auto isFlag() const -> bool { return true; } -}; + struct BoundRef : NonCopyable { + virtual ~BoundRef() = default; + virtual auto isContainer() const -> bool { return false; } + virtual auto isFlag() const -> bool { return false; } + }; + struct BoundValueRefBase : BoundRef { + virtual auto setValue(std::string const& arg) -> ParserResult = 0; + }; + struct BoundFlagRefBase : BoundRef { + virtual auto setFlag(bool flag) -> ParserResult = 0; + virtual auto isFlag() const -> bool { return true; } + }; -template -struct BoundValueRef : BoundValueRefBase { -T &m_ref; + template struct BoundValueRef : BoundValueRefBase { + T& m_ref; -explicit BoundValueRef( T &ref ) : m_ref( ref ) {} + explicit BoundValueRef(T& ref) : m_ref(ref) {} -auto setValue( std::string const &arg ) -> ParserResult override { -return convertInto( arg, m_ref ); -} -}; + auto setValue(std::string const& arg) -> ParserResult override { return convertInto(arg, m_ref); } + }; -template -struct BoundValueRef> : BoundValueRefBase { -std::vector &m_ref; + template struct BoundValueRef> : BoundValueRefBase { + std::vector& m_ref; -explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} + explicit BoundValueRef(std::vector& ref) : m_ref(ref) {} -auto isContainer() const -> bool override { return true; } + auto isContainer() const -> bool override { return true; } -auto setValue( std::string const &arg ) -> ParserResult override { -T temp; -auto result = convertInto( arg, temp ); -if( result ) -m_ref.push_back( temp ); -return result; -} -}; + auto setValue(std::string const& arg) -> ParserResult override { + T temp; + auto result = convertInto(arg, temp); + if (result) + m_ref.push_back(temp); + return result; + } + }; -struct BoundFlagRef : BoundFlagRefBase { -bool &m_ref; + struct BoundFlagRef : BoundFlagRefBase { + bool& m_ref; -explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} + explicit BoundFlagRef(bool& ref) : m_ref(ref) {} -auto setFlag( bool flag ) -> ParserResult override { -m_ref = flag; -return ParserResult::ok( ParseResultType::Matched ); -} -}; + auto setFlag(bool flag) -> ParserResult override { + m_ref = flag; + return ParserResult::ok(ParseResultType::Matched); + } + }; -template -struct LambdaInvoker { -static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); + template struct LambdaInvoker { + static_assert(std::is_same::value, + "Lambda must return void or clara::ParserResult"); -template -static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { -return lambda( arg ); -} -}; + template + static auto invoke(L const& lambda, ArgType const& arg) -> ParserResult { + return lambda(arg); + } + }; -template<> -struct LambdaInvoker { -template -static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { -lambda( arg ); -return ParserResult::ok( ParseResultType::Matched ); -} -}; + template <> struct LambdaInvoker { + template + static auto invoke(L const& lambda, ArgType const& arg) -> ParserResult { + lambda(arg); + return ParserResult::ok(ParseResultType::Matched); + } + }; -template -inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { -ArgType temp{}; -auto result = convertInto( arg, temp ); -return !result -? result -: LambdaInvoker::ReturnType>::invoke( lambda, temp ); -} + template + inline auto invokeLambda(L const& lambda, std::string const& arg) -> ParserResult { + ArgType temp{}; + auto result = convertInto(arg, temp); + return !result ? result + : LambdaInvoker::ReturnType>::invoke(lambda, temp); + } -template -struct BoundLambda : BoundValueRefBase { -L m_lambda; + template struct BoundLambda : BoundValueRefBase { + L m_lambda; -static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); -explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} + static_assert(UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument"); + explicit BoundLambda(L const& lambda) : m_lambda(lambda) {} -auto setValue( std::string const &arg ) -> ParserResult override { -return invokeLambda::ArgType>( m_lambda, arg ); -} -}; + auto setValue(std::string const& arg) -> ParserResult override { + return invokeLambda::ArgType>(m_lambda, arg); + } + }; -template -struct BoundFlagLambda : BoundFlagRefBase { -L m_lambda; + template struct BoundFlagLambda : BoundFlagRefBase { + L m_lambda; -static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); -static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); + static_assert(UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument"); + static_assert(std::is_same::ArgType, bool>::value, + "flags must be boolean"); -explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} + explicit BoundFlagLambda(L const& lambda) : m_lambda(lambda) {} -auto setFlag( bool flag ) -> ParserResult override { -return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); -} -}; + auto setFlag(bool flag) -> ParserResult override { + return LambdaInvoker::ReturnType>::invoke(m_lambda, flag); + } + }; -enum class Optionality { Optional, Required }; + enum class Optionality { Optional, Required }; -struct Parser; + struct Parser; -class ParserBase { -public: -virtual ~ParserBase() = default; -virtual auto validate() const -> Result { return Result::ok(); } -virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; -virtual auto cardinality() const -> size_t { return 1; } + class ParserBase { + public: + virtual ~ParserBase() = default; + virtual auto validate() const -> Result { return Result::ok(); } + virtual auto parse(std::string const& exeName, TokenStream const& tokens) const + -> InternalParseResult = 0; + virtual auto cardinality() const -> size_t { return 1; } -auto parse( Args const &args ) const -> InternalParseResult { -return parse( args.exeName(), TokenStream( args ) ); -} -}; + auto parse(Args const& args) const -> InternalParseResult { + return parse(args.exeName(), TokenStream(args)); + } + }; -template -class ComposableParserImpl : public ParserBase { -public: -template -auto operator|( T const &other ) const -> Parser; + template class ComposableParserImpl : public ParserBase { + public: + template auto operator|(T const& other) const -> Parser; -template -auto operator+( T const &other ) const -> Parser; -}; + template auto operator+(T const& other) const -> Parser; + }; -// Common code and state for Args and Opts -template -class ParserRefImpl : public ComposableParserImpl { -protected: -Optionality m_optionality = Optionality::Optional; -std::shared_ptr m_ref; -std::string m_hint; -std::string m_description; + // Common code and state for Args and Opts + template class ParserRefImpl : public ComposableParserImpl { + protected: + Optionality m_optionality = Optionality::Optional; + std::shared_ptr m_ref; + std::string m_hint; + std::string m_description; -explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + explicit ParserRefImpl(std::shared_ptr const& ref) : m_ref(ref) {} -public: -template -ParserRefImpl( T &ref, std::string const &hint ) -: m_ref( std::make_shared>( ref ) ), -m_hint( hint ) -{} + public: + template + ParserRefImpl(T& ref, std::string const& hint) + : m_ref(std::make_shared>(ref)), m_hint(hint) {} -template -ParserRefImpl( LambdaT const &ref, std::string const &hint ) -: m_ref( std::make_shared>( ref ) ), -m_hint(hint) -{} + template + ParserRefImpl(LambdaT const& ref, std::string const& hint) + : m_ref(std::make_shared>(ref)), m_hint(hint) {} -auto operator()( std::string const &description ) -> DerivedT & { -m_description = description; -return static_cast( *this ); -} + auto operator()(std::string const& description) -> DerivedT& { + m_description = description; + return static_cast(*this); + } -auto optional() -> DerivedT & { -m_optionality = Optionality::Optional; -return static_cast( *this ); -}; + auto optional() -> DerivedT& { + m_optionality = Optionality::Optional; + return static_cast(*this); + }; -auto required() -> DerivedT & { -m_optionality = Optionality::Required; -return static_cast( *this ); -}; + auto required() -> DerivedT& { + m_optionality = Optionality::Required; + return static_cast(*this); + }; -auto isOptional() const -> bool { -return m_optionality == Optionality::Optional; -} + auto isOptional() const -> bool { return m_optionality == Optionality::Optional; } -auto cardinality() const -> size_t override { -if( m_ref->isContainer() ) -return 0; -else -return 1; -} + auto cardinality() const -> size_t override { + if (m_ref->isContainer()) + return 0; + else + return 1; + } -auto hint() const -> std::string { return m_hint; } -}; + auto hint() const -> std::string { return m_hint; } + }; -class ExeName : public ComposableParserImpl { -std::shared_ptr m_name; -std::shared_ptr m_ref; + class ExeName : public ComposableParserImpl { + std::shared_ptr m_name; + std::shared_ptr m_ref; -template -static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { -return std::make_shared>( lambda) ; -} + template + static auto makeRef(LambdaT const& lambda) -> std::shared_ptr { + return std::make_shared>(lambda); + } -public: -ExeName() : m_name( std::make_shared( "" ) ) {} + public: + ExeName() : m_name(std::make_shared("")) {} -explicit ExeName( std::string &ref ) : ExeName() { -m_ref = std::make_shared>( ref ); -} + explicit ExeName(std::string& ref) : ExeName() { + m_ref = std::make_shared>(ref); + } -template -explicit ExeName( LambdaT const& lambda ) : ExeName() { -m_ref = std::make_shared>( lambda ); -} + template explicit ExeName(LambdaT const& lambda) : ExeName() { + m_ref = std::make_shared>(lambda); + } -// The exe name is not parsed out of the normal tokens, but is handled specially -auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { -return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); -} + // The exe name is not parsed out of the normal tokens, but is handled specially + auto parse(std::string const&, TokenStream const& tokens) const -> InternalParseResult override { + return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens)); + } -auto name() const -> std::string { return *m_name; } -auto set( std::string const& newName ) -> ParserResult { + auto name() const -> std::string { return *m_name; } + auto set(std::string const& newName) -> ParserResult { -auto lastSlash = newName.find_last_of( "\\/" ); -auto filename = ( lastSlash == std::string::npos ) -? newName -: newName.substr( lastSlash+1 ); + auto lastSlash = newName.find_last_of("\\/"); + auto filename = (lastSlash == std::string::npos) ? newName : newName.substr(lastSlash + 1); -*m_name = filename; -if( m_ref ) -return m_ref->setValue( filename ); -else -return ParserResult::ok( ParseResultType::Matched ); -} -}; + *m_name = filename; + if (m_ref) + return m_ref->setValue(filename); + else + return ParserResult::ok(ParseResultType::Matched); + } + }; -class Arg : public ParserRefImpl { -public: -using ParserRefImpl::ParserRefImpl; + class Arg : public ParserRefImpl { + public: + using ParserRefImpl::ParserRefImpl; -auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { -auto validationResult = validate(); -if( !validationResult ) -return InternalParseResult( validationResult ); + auto parse(std::string const&, TokenStream const& tokens) const -> InternalParseResult override { + auto validationResult = validate(); + if (!validationResult) + return InternalParseResult(validationResult); -auto remainingTokens = tokens; -auto const &token = *remainingTokens; -if( token.type != TokenType::Argument ) -return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + auto remainingTokens = tokens; + auto const& token = *remainingTokens; + if (token.type != TokenType::Argument) + return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens)); -assert( !m_ref->isFlag() ); -auto valueRef = static_cast( m_ref.get() ); + assert(!m_ref->isFlag()); + auto valueRef = static_cast(m_ref.get()); -auto result = valueRef->setValue( remainingTokens->token ); -if( !result ) -return InternalParseResult( result ); -else -return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); -} -}; + auto result = valueRef->setValue(remainingTokens->token); + if (!result) + return InternalParseResult(result); + else + return InternalParseResult::ok(ParseState(ParseResultType::Matched, ++remainingTokens)); + } + }; -inline auto normaliseOpt( std::string const &optName ) -> std::string { + inline auto normaliseOpt(std::string const& optName) -> std::string { #ifdef CATCH_PLATFORM_WINDOWS -if( optName[0] == '/' ) -return "-" + optName.substr( 1 ); -else + if (optName[0] == '/') + return "-" + optName.substr(1); + else #endif -return optName; -} + return optName; + } -class Opt : public ParserRefImpl { -protected: -std::vector m_optNames; + class Opt : public ParserRefImpl { + protected: + std::vector m_optNames; -public: -template -explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} + public: + template + explicit Opt(LambdaT const& ref) : ParserRefImpl(std::make_shared>(ref)) {} -explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} + explicit Opt(bool& ref) : ParserRefImpl(std::make_shared(ref)) {} -template -Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + template + Opt(LambdaT const& ref, std::string const& hint) : ParserRefImpl(ref, hint) {} -template -Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + template Opt(T& ref, std::string const& hint) : ParserRefImpl(ref, hint) {} -auto operator[]( std::string const &optName ) -> Opt & { -m_optNames.push_back( optName ); -return *this; -} + auto operator[](std::string const& optName) -> Opt& { + m_optNames.push_back(optName); + return *this; + } -auto getHelpColumns() const -> std::vector { -std::ostringstream oss; -bool first = true; -for( auto const &opt : m_optNames ) { -if (first) -first = false; -else -oss << ", "; -oss << opt; -} -if( !m_hint.empty() ) -oss << " <" << m_hint << ">"; -return { { oss.str(), m_description } }; -} + auto getHelpColumns() const -> std::vector { + std::ostringstream oss; + bool first = true; + for (auto const& opt : m_optNames) { + if (first) + first = false; + else + oss << ", "; + oss << opt; + } + if (!m_hint.empty()) + oss << " <" << m_hint << ">"; + return {{oss.str(), m_description}}; + } -auto isMatch( std::string const &optToken ) const -> bool { -auto normalisedToken = normaliseOpt( optToken ); -for( auto const &name : m_optNames ) { -if( normaliseOpt( name ) == normalisedToken ) -return true; -} -return false; -} + auto isMatch(std::string const& optToken) const -> bool { + auto normalisedToken = normaliseOpt(optToken); + for (auto const& name : m_optNames) { + if (normaliseOpt(name) == normalisedToken) + return true; + } + return false; + } -using ParserBase::parse; + using ParserBase::parse; -auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { -auto validationResult = validate(); -if( !validationResult ) -return InternalParseResult( validationResult ); + auto parse(std::string const&, TokenStream const& tokens) const -> InternalParseResult override { + auto validationResult = validate(); + if (!validationResult) + return InternalParseResult(validationResult); -auto remainingTokens = tokens; -if( remainingTokens && remainingTokens->type == TokenType::Option ) { -auto const &token = *remainingTokens; -if( isMatch(token.token ) ) { -if( m_ref->isFlag() ) { -auto flagRef = static_cast( m_ref.get() ); -auto result = flagRef->setFlag( true ); -if( !result ) -return InternalParseResult( result ); -if( result.value() == ParseResultType::ShortCircuitAll ) -return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); -} else { -auto valueRef = static_cast( m_ref.get() ); -++remainingTokens; -if( !remainingTokens ) -return InternalParseResult::runtimeError( "Expected argument following " + token.token ); -auto const &argToken = *remainingTokens; -if( argToken.type != TokenType::Argument ) -return InternalParseResult::runtimeError( "Expected argument following " + token.token ); -auto result = valueRef->setValue( argToken.token ); -if( !result ) -return InternalParseResult( result ); -if( result.value() == ParseResultType::ShortCircuitAll ) -return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); -} -return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); -} -} -return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); -} + auto remainingTokens = tokens; + if (remainingTokens && remainingTokens->type == TokenType::Option) { + auto const& token = *remainingTokens; + if (isMatch(token.token)) { + if (m_ref->isFlag()) { + auto flagRef = static_cast(m_ref.get()); + auto result = flagRef->setFlag(true); + if (!result) + return InternalParseResult(result); + if (result.value() == ParseResultType::ShortCircuitAll) + return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); + } else { + auto valueRef = static_cast(m_ref.get()); + ++remainingTokens; + if (!remainingTokens) + return InternalParseResult::runtimeError("Expected argument following " + + token.token); + auto const& argToken = *remainingTokens; + if (argToken.type != TokenType::Argument) + return InternalParseResult::runtimeError("Expected argument following " + + token.token); + auto result = valueRef->setValue(argToken.token); + if (!result) + return InternalParseResult(result); + if (result.value() == ParseResultType::ShortCircuitAll) + return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); + } + return InternalParseResult::ok(ParseState(ParseResultType::Matched, ++remainingTokens)); + } + } + return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens)); + } -auto validate() const -> Result override { -if( m_optNames.empty() ) -return Result::logicError( "No options supplied to Opt" ); -for( auto const &name : m_optNames ) { -if( name.empty() ) -return Result::logicError( "Option name cannot be empty" ); + auto validate() const -> Result override { + if (m_optNames.empty()) + return Result::logicError("No options supplied to Opt"); + for (auto const& name : m_optNames) { + if (name.empty()) + return Result::logicError("Option name cannot be empty"); #ifdef CATCH_PLATFORM_WINDOWS -if( name[0] != '-' && name[0] != '/' ) -return Result::logicError( "Option name must begin with '-' or '/'" ); + if (name[0] != '-' && name[0] != '/') + return Result::logicError("Option name must begin with '-' or '/'"); #else -if( name[0] != '-' ) -return Result::logicError( "Option name must begin with '-'" ); + if (name[0] != '-') + return Result::logicError("Option name must begin with '-'"); #endif -} -return ParserRefImpl::validate(); -} -}; + } + return ParserRefImpl::validate(); + } + }; -struct Help : Opt { -Help( bool &showHelpFlag ) -: Opt([&]( bool flag ) { -showHelpFlag = flag; -return ParserResult::ok( ParseResultType::ShortCircuitAll ); -}) -{ -static_cast( *this ) -("display usage information") -["-?"]["-h"]["--help"] -.optional(); -} -}; + struct Help : Opt { + Help(bool& showHelpFlag) + : Opt([&](bool flag) { + showHelpFlag = flag; + return ParserResult::ok(ParseResultType::ShortCircuitAll); + }) { + static_cast (*this)("display usage information")["-?"]["-h"]["--help"].optional(); + } + }; -struct Parser : ParserBase { + struct Parser : ParserBase { -mutable ExeName m_exeName; -std::vector m_options; -std::vector m_args; + mutable ExeName m_exeName; + std::vector m_options; + std::vector m_args; -auto operator|=( ExeName const &exeName ) -> Parser & { -m_exeName = exeName; -return *this; -} + auto operator|=(ExeName const& exeName) -> Parser& { + m_exeName = exeName; + return *this; + } -auto operator|=( Arg const &arg ) -> Parser & { -m_args.push_back(arg); -return *this; -} + auto operator|=(Arg const& arg) -> Parser& { + m_args.push_back(arg); + return *this; + } -auto operator|=( Opt const &opt ) -> Parser & { -m_options.push_back(opt); -return *this; -} + auto operator|=(Opt const& opt) -> Parser& { + m_options.push_back(opt); + return *this; + } -auto operator|=( Parser const &other ) -> Parser & { -m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); -m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); -return *this; -} + auto operator|=(Parser const& other) -> Parser& { + m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); + m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); + return *this; + } -template -auto operator|( T const &other ) const -> Parser { -return Parser( *this ) |= other; -} + template auto operator|(T const& other) const -> Parser { return Parser(*this) |= other; } -// Forward deprecated interface with '+' instead of '|' -template -auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } -template -auto operator+( T const &other ) const -> Parser { return operator|( other ); } + // Forward deprecated interface with '+' instead of '|' + template auto operator+=(T const& other) -> Parser& { return operator|=(other); } + template auto operator+(T const& other) const -> Parser { return operator|(other); } -auto getHelpColumns() const -> std::vector { -std::vector cols; -for (auto const &o : m_options) { -auto childCols = o.getHelpColumns(); -cols.insert( cols.end(), childCols.begin(), childCols.end() ); -} -return cols; -} + auto getHelpColumns() const -> std::vector { + std::vector cols; + for (auto const& o : m_options) { + auto childCols = o.getHelpColumns(); + cols.insert(cols.end(), childCols.begin(), childCols.end()); + } + return cols; + } -void writeToStream( std::ostream &os ) const { -if (!m_exeName.name().empty()) { -os << "usage:\n" << " " << m_exeName.name() << " "; -bool required = true, first = true; -for( auto const &arg : m_args ) { -if (first) -first = false; -else -os << " "; -if( arg.isOptional() && required ) { -os << "["; -required = false; -} -os << "<" << arg.hint() << ">"; -if( arg.cardinality() == 0 ) -os << " ... "; -} -if( !required ) -os << "]"; -if( !m_options.empty() ) -os << " options"; -os << "\n\nwhere options are:" << std::endl; -} + void writeToStream(std::ostream& os) const { + if (!m_exeName.name().empty()) { + os << "usage:\n" + << " " << m_exeName.name() << " "; + bool required = true, first = true; + for (auto const& arg : m_args) { + if (first) + first = false; + else + os << " "; + if (arg.isOptional() && required) { + os << "["; + required = false; + } + os << "<" << arg.hint() << ">"; + if (arg.cardinality() == 0) + os << " ... "; + } + if (!required) + os << "]"; + if (!m_options.empty()) + os << " options"; + os << "\n\nwhere options are:" << std::endl; + } -auto rows = getHelpColumns(); -size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; -size_t optWidth = 0; -for( auto const &cols : rows ) -optWidth = (std::max)(optWidth, cols.left.size() + 2); + auto rows = getHelpColumns(); + size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; + size_t optWidth = 0; + for (auto const& cols : rows) + optWidth = (std::max)(optWidth, cols.left.size() + 2); -optWidth = (std::min)(optWidth, consoleWidth/2); + optWidth = (std::min)(optWidth, consoleWidth / 2); -for( auto const &cols : rows ) { -auto row = -TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + -TextFlow::Spacer(4) + -TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); -os << row << std::endl; -} -} + for (auto const& cols : rows) { + auto row = TextFlow::Column(cols.left).width(optWidth).indent(2) + TextFlow::Spacer(4) + + TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth); + os << row << std::endl; + } + } -friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { -parser.writeToStream( os ); -return os; -} + friend auto operator<<(std::ostream& os, Parser const& parser) -> std::ostream& { + parser.writeToStream(os); + return os; + } -auto validate() const -> Result override { -for( auto const &opt : m_options ) { -auto result = opt.validate(); -if( !result ) -return result; -} -for( auto const &arg : m_args ) { -auto result = arg.validate(); -if( !result ) -return result; -} -return Result::ok(); -} + auto validate() const -> Result override { + for (auto const& opt : m_options) { + auto result = opt.validate(); + if (!result) + return result; + } + for (auto const& arg : m_args) { + auto result = arg.validate(); + if (!result) + return result; + } + return Result::ok(); + } -using ParserBase::parse; + using ParserBase::parse; -auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { + auto parse(std::string const& exeName, TokenStream const& tokens) const + -> InternalParseResult override { -struct ParserInfo { -ParserBase const* parser = nullptr; -size_t count = 0; -}; -const size_t totalParsers = m_options.size() + m_args.size(); -assert( totalParsers < 512 ); -// ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do -ParserInfo parseInfos[512]; + struct ParserInfo { + ParserBase const* parser = nullptr; + size_t count = 0; + }; + const size_t totalParsers = m_options.size() + m_args.size(); + assert(totalParsers < 512); + // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do + ParserInfo parseInfos[512]; -{ -size_t i = 0; -for (auto const &opt : m_options) parseInfos[i++].parser = &opt; -for (auto const &arg : m_args) parseInfos[i++].parser = &arg; -} + { + size_t i = 0; + for (auto const& opt : m_options) + parseInfos[i++].parser = &opt; + for (auto const& arg : m_args) + parseInfos[i++].parser = &arg; + } -m_exeName.set( exeName ); + m_exeName.set(exeName); -auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); -while( result.value().remainingTokens() ) { -bool tokenParsed = false; + auto result = InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens)); + while (result.value().remainingTokens()) { + bool tokenParsed = false; -for( size_t i = 0; i < totalParsers; ++i ) { -auto& parseInfo = parseInfos[i]; -if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { -result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); -if (!result) -return result; -if (result.value().type() != ParseResultType::NoMatch) { -tokenParsed = true; -++parseInfo.count; -break; -} -} -} + for (size_t i = 0; i < totalParsers; ++i) { + auto& parseInfo = parseInfos[i]; + if (parseInfo.parser->cardinality() == 0 || + parseInfo.count < parseInfo.parser->cardinality()) { + result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); + if (!result) + return result; + if (result.value().type() != ParseResultType::NoMatch) { + tokenParsed = true; + ++parseInfo.count; + break; + } + } + } -if( result.value().type() == ParseResultType::ShortCircuitAll ) -return result; -if( !tokenParsed ) -return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); -} -// !TBD Check missing required options -return result; -} -}; + if (result.value().type() == ParseResultType::ShortCircuitAll) + return result; + if (!tokenParsed) + return InternalParseResult::runtimeError("Unrecognised token: " + + result.value().remainingTokens()->token); + } + // !TBD Check missing required options + return result; + } + }; -template -template -auto ComposableParserImpl::operator|( T const &other ) const -> Parser { -return Parser() | static_cast( *this ) | other; -} -} // namespace detail + template + template + auto ComposableParserImpl::operator|(T const& other) const -> Parser { + return Parser() | static_cast(*this) | other; + } + } // namespace detail -// A Combined parser -using detail::Parser; + // A Combined parser + using detail::Parser; -// A parser for options -using detail::Opt; + // A parser for options + using detail::Opt; -// A parser for arguments -using detail::Arg; + // A parser for arguments + using detail::Arg; -// Wrapper for argc, argv from main() -using detail::Args; + // Wrapper for argc, argv from main() + using detail::Args; -// Specifies the name of the executable -using detail::ExeName; + // Specifies the name of the executable + using detail::ExeName; -// Convenience wrapper for option parser that specifies the help option -using detail::Help; + // Convenience wrapper for option parser that specifies the help option + using detail::Help; -// enum of result types from a parse -using detail::ParseResultType; + // enum of result types from a parse + using detail::ParseResultType; -// Result type for parser operation -using detail::ParserResult; + // Result type for parser operation + using detail::ParserResult; -}} // namespace Catch::clara + } +} // namespace Catch::clara // end clara.hpp #ifdef __clang__ @@ -9605,217 +9413,166 @@ using detail::ParserResult; // end catch_clara.h namespace Catch { -clara::Parser makeCommandLineParser( ConfigData& config ); + clara::Parser makeCommandLineParser(ConfigData& config); } // end namespace Catch // end catch_commandline.h -#include #include +#include namespace Catch { -clara::Parser makeCommandLineParser( ConfigData& config ) { + clara::Parser makeCommandLineParser(ConfigData& config) { -using namespace clara; + using namespace clara; -auto const setWarning = [&]( std::string const& warning ) { -auto warningSet = [&]() { -if( warning == "NoAssertions" ) -return WarnAbout::NoAssertions; + auto const setWarning = [&](std::string const& warning) { + auto warningSet = [&]() { + if (warning == "NoAssertions") + return WarnAbout::NoAssertions; -if ( warning == "NoTests" ) -return WarnAbout::NoTests; + if (warning == "NoTests") + return WarnAbout::NoTests; -return WarnAbout::Nothing; -}(); + return WarnAbout::Nothing; + }(); -if (warningSet == WarnAbout::Nothing) -return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); -config.warnings = static_cast( config.warnings | warningSet ); -return ParserResult::ok( ParseResultType::Matched ); -}; -auto const loadTestNamesFromFile = [&]( std::string const& filename ) { -std::ifstream f( filename.c_str() ); -if( !f.is_open() ) -return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); + if (warningSet == WarnAbout::Nothing) + return ParserResult::runtimeError("Unrecognised warning: '" + warning + "'"); + config.warnings = static_cast(config.warnings | warningSet); + return ParserResult::ok(ParseResultType::Matched); + }; + auto const loadTestNamesFromFile = [&](std::string const& filename) { + std::ifstream f(filename.c_str()); + if (!f.is_open()) + return ParserResult::runtimeError("Unable to load input file: '" + filename + "'"); -std::string line; -while( std::getline( f, line ) ) { -line = trim(line); -if( !line.empty() && !startsWith( line, '#' ) ) { -if( !startsWith( line, '"' ) ) -line = '"' + line + '"'; -config.testsOrTags.push_back( line ); -config.testsOrTags.push_back( "," ); + std::string line; + while (std::getline(f, line)) { + line = trim(line); + if (!line.empty() && !startsWith(line, '#')) { + if (!startsWith(line, '"')) + line = '"' + line + '"'; + config.testsOrTags.push_back(line); + config.testsOrTags.push_back(","); + } + } + // Remove comma in the end + if (!config.testsOrTags.empty()) + config.testsOrTags.erase(config.testsOrTags.end() - 1); -} -} -//Remove comma in the end -if(!config.testsOrTags.empty()) -config.testsOrTags.erase( config.testsOrTags.end()-1 ); + return ParserResult::ok(ParseResultType::Matched); + }; + auto const setTestOrder = [&](std::string const& order) { + if (startsWith("declared", order)) + config.runOrder = RunTests::InDeclarationOrder; + else if (startsWith("lexical", order)) + config.runOrder = RunTests::InLexicographicalOrder; + else if (startsWith("random", order)) + config.runOrder = RunTests::InRandomOrder; + else + return clara::ParserResult::runtimeError("Unrecognised ordering: '" + order + "'"); + return ParserResult::ok(ParseResultType::Matched); + }; + auto const setRngSeed = [&](std::string const& seed) { + if (seed != "time") + return clara::detail::convertInto(seed, config.rngSeed); + config.rngSeed = static_cast(std::time(nullptr)); + return ParserResult::ok(ParseResultType::Matched); + }; + auto const setColourUsage = [&](std::string const& useColour) { + auto mode = toLower(useColour); -return ParserResult::ok( ParseResultType::Matched ); -}; -auto const setTestOrder = [&]( std::string const& order ) { -if( startsWith( "declared", order ) ) -config.runOrder = RunTests::InDeclarationOrder; -else if( startsWith( "lexical", order ) ) -config.runOrder = RunTests::InLexicographicalOrder; -else if( startsWith( "random", order ) ) -config.runOrder = RunTests::InRandomOrder; -else -return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); -return ParserResult::ok( ParseResultType::Matched ); -}; -auto const setRngSeed = [&]( std::string const& seed ) { -if( seed != "time" ) -return clara::detail::convertInto( seed, config.rngSeed ); -config.rngSeed = static_cast( std::time(nullptr) ); -return ParserResult::ok( ParseResultType::Matched ); -}; -auto const setColourUsage = [&]( std::string const& useColour ) { -auto mode = toLower( useColour ); + if (mode == "yes") + config.useColour = UseColour::Yes; + else if (mode == "no") + config.useColour = UseColour::No; + else if (mode == "auto") + config.useColour = UseColour::Auto; + else + return ParserResult::runtimeError("colour mode must be one of: auto, yes or no. '" + useColour + + "' not recognised"); + return ParserResult::ok(ParseResultType::Matched); + }; + auto const setWaitForKeypress = [&](std::string const& keypress) { + auto keypressLc = toLower(keypress); + if (keypressLc == "start") + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if (keypressLc == "exit") + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if (keypressLc == "both") + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else + return ParserResult::runtimeError("keypress argument must be one of: start, exit or both. '" + + keypress + "' not recognised"); + return ParserResult::ok(ParseResultType::Matched); + }; + auto const setVerbosity = [&](std::string const& verbosity) { + auto lcVerbosity = toLower(verbosity); + if (lcVerbosity == "quiet") + config.verbosity = Verbosity::Quiet; + else if (lcVerbosity == "normal") + config.verbosity = Verbosity::Normal; + else if (lcVerbosity == "high") + config.verbosity = Verbosity::High; + else + return ParserResult::runtimeError("Unrecognised verbosity, '" + verbosity + "'"); + return ParserResult::ok(ParseResultType::Matched); + }; + auto const setReporter = [&](std::string const& reporter) { + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); -if( mode == "yes" ) -config.useColour = UseColour::Yes; -else if( mode == "no" ) -config.useColour = UseColour::No; -else if( mode == "auto" ) -config.useColour = UseColour::Auto; -else -return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); -return ParserResult::ok( ParseResultType::Matched ); -}; -auto const setWaitForKeypress = [&]( std::string const& keypress ) { -auto keypressLc = toLower( keypress ); -if( keypressLc == "start" ) -config.waitForKeypress = WaitForKeypress::BeforeStart; -else if( keypressLc == "exit" ) -config.waitForKeypress = WaitForKeypress::BeforeExit; -else if( keypressLc == "both" ) -config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; -else -return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); -return ParserResult::ok( ParseResultType::Matched ); -}; -auto const setVerbosity = [&]( std::string const& verbosity ) { -auto lcVerbosity = toLower( verbosity ); -if( lcVerbosity == "quiet" ) -config.verbosity = Verbosity::Quiet; -else if( lcVerbosity == "normal" ) -config.verbosity = Verbosity::Normal; -else if( lcVerbosity == "high" ) -config.verbosity = Verbosity::High; -else -return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); -return ParserResult::ok( ParseResultType::Matched ); -}; -auto const setReporter = [&]( std::string const& reporter ) { -IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + auto lcReporter = toLower(reporter); + auto result = factories.find(lcReporter); -auto lcReporter = toLower( reporter ); -auto result = factories.find( lcReporter ); + if (factories.end() != result) + config.reporterName = lcReporter; + else + return ParserResult::runtimeError("Unrecognized reporter, '" + reporter + + "'. Check available with --list-reporters"); + return ParserResult::ok(ParseResultType::Matched); + }; -if( factories.end() != result ) -config.reporterName = lcReporter; -else -return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" ); -return ParserResult::ok( ParseResultType::Matched ); -}; + auto cli = + ExeName(config.processName) | Help(config.showHelp) | + Opt(config.listTests)["-l"]["--list-tests"]("list all/matching test cases") | + Opt(config.listTags)["-t"]["--list-tags"]("list all/matching tags") | + Opt(config.showSuccessfulTests)["-s"]["--success"]("include successful tests in output") | + Opt(config.shouldDebugBreak)["-b"]["--break"]("break into debugger on failure") | + Opt(config.noThrow)["-e"]["--nothrow"]("skip exception tests") | + Opt(config.showInvisibles)["-i"]["--invisibles"]("show invisibles (tabs, newlines)") | + Opt(config.outputFilename, "filename")["-o"]["--out"]("output filename") | + Opt(setReporter, "name")["-r"]["--reporter"]("reporter to use (defaults to console)") | + Opt(config.name, "name")["-n"]["--name"]("suite name") | + Opt([&](bool) { config.abortAfter = 1; })["-a"]["--abort"]("abort at first failure") | + Opt([&](int x) { config.abortAfter = x; }, "no. failures")["-x"]["--abortx"]("abort after x failures") | + Opt(setWarning, "warning name")["-w"]["--warn"]("enable warnings") | + Opt([&](bool flag) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, + "yes|no")["-d"]["--durations"]("show test durations") | + Opt(loadTestNamesFromFile, "filename")["-f"]["--input-file"]("load test names to run from a file") | + Opt(config.filenamesAsTags)["-#"]["--filenames-as-tags"]("adds a tag for the filename") | + Opt(config.sectionsToRun, "section name")["-c"]["--section"]("specify section to run") | + Opt(setVerbosity, "quiet|normal|high")["-v"]["--verbosity"]("set output verbosity") | + Opt(config.listTestNamesOnly)["--list-test-names-only"]("list all/matching test cases names only") | + Opt(config.listReporters)["--list-reporters"]("list all reporters") | + Opt(setTestOrder, "decl|lex|rand")["--order"]("test case order (defaults to decl)") | + Opt(setRngSeed, "'time'|number")["--rng-seed"]("set a specific seed for random numbers") | + Opt(setColourUsage, "yes|no")["--use-colour"]("should output be colourised") | + Opt(config.libIdentify)["--libidentify"]("report name and version according to libidentify standard") | + Opt(setWaitForKeypress, "start|exit|both")["--wait-for-keypress"]("waits for a keypress before exiting") | + Opt(config.benchmarkSamples, + "samples")["--benchmark-samples"]("number of samples to collect (default: 100)") | + Opt(config.benchmarkResamples, + "resamples")["--benchmark-resamples"]("number of resamples for the bootstrap (default: 100000)") | + Opt(config.benchmarkConfidenceInterval, "confidence interval")["--benchmark-confidence-interval"]( + "confidence interval for the bootstrap (between 0 and 1, default: 0.95)") | + Opt(config.benchmarkNoAnalysis)["--benchmark-no-analysis"]( + "perform only measurements; do not perform any analysis") | + Arg(config.testsOrTags, "test name|pattern|tags")("which test or tests to use"); -auto cli -= ExeName( config.processName ) -| Help( config.showHelp ) -| Opt( config.listTests ) -["-l"]["--list-tests"] -( "list all/matching test cases" ) -| Opt( config.listTags ) -["-t"]["--list-tags"] -( "list all/matching tags" ) -| Opt( config.showSuccessfulTests ) -["-s"]["--success"] -( "include successful tests in output" ) -| Opt( config.shouldDebugBreak ) -["-b"]["--break"] -( "break into debugger on failure" ) -| Opt( config.noThrow ) -["-e"]["--nothrow"] -( "skip exception tests" ) -| Opt( config.showInvisibles ) -["-i"]["--invisibles"] -( "show invisibles (tabs, newlines)" ) -| Opt( config.outputFilename, "filename" ) -["-o"]["--out"] -( "output filename" ) -| Opt( setReporter, "name" ) -["-r"]["--reporter"] -( "reporter to use (defaults to console)" ) -| Opt( config.name, "name" ) -["-n"]["--name"] -( "suite name" ) -| Opt( [&]( bool ){ config.abortAfter = 1; } ) -["-a"]["--abort"] -( "abort at first failure" ) -| Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) -["-x"]["--abortx"] -( "abort after x failures" ) -| Opt( setWarning, "warning name" ) -["-w"]["--warn"] -( "enable warnings" ) -| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) -["-d"]["--durations"] -( "show test durations" ) -| Opt( loadTestNamesFromFile, "filename" ) -["-f"]["--input-file"] -( "load test names to run from a file" ) -| Opt( config.filenamesAsTags ) -["-#"]["--filenames-as-tags"] -( "adds a tag for the filename" ) -| Opt( config.sectionsToRun, "section name" ) -["-c"]["--section"] -( "specify section to run" ) -| Opt( setVerbosity, "quiet|normal|high" ) -["-v"]["--verbosity"] -( "set output verbosity" ) -| Opt( config.listTestNamesOnly ) -["--list-test-names-only"] -( "list all/matching test cases names only" ) -| Opt( config.listReporters ) -["--list-reporters"] -( "list all reporters" ) -| Opt( setTestOrder, "decl|lex|rand" ) -["--order"] -( "test case order (defaults to decl)" ) -| Opt( setRngSeed, "'time'|number" ) -["--rng-seed"] -( "set a specific seed for random numbers" ) -| Opt( setColourUsage, "yes|no" ) -["--use-colour"] -( "should output be colourised" ) -| Opt( config.libIdentify ) -["--libidentify"] -( "report name and version according to libidentify standard" ) -| Opt( setWaitForKeypress, "start|exit|both" ) -["--wait-for-keypress"] -( "waits for a keypress before exiting" ) -| Opt( config.benchmarkSamples, "samples" ) -["--benchmark-samples"] -( "number of samples to collect (default: 100)" ) -| Opt( config.benchmarkResamples, "resamples" ) -["--benchmark-resamples"] -( "number of resamples for the bootstrap (default: 100000)" ) -| Opt( config.benchmarkConfidenceInterval, "confidence interval" ) -["--benchmark-confidence-interval"] -( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" ) -| Opt( config.benchmarkNoAnalysis ) -["--benchmark-no-analysis"] -( "perform only measurements; do not perform any analysis" ) -| Arg( config.testsOrTags, "test name|pattern|tags" ) -( "which test or tests to use" ); - -return cli; -} + return cli; + } } // end namespace Catch // end catch_commandline.cpp @@ -9826,30 +9583,28 @@ return cli; namespace Catch { -bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { -return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); -} -bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { -// We can assume that the same file will usually have the same pointer. -// Thus, if the pointers are the same, there is no point in calling the strcmp -return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); -} + bool SourceLineInfo::operator==(SourceLineInfo const& other) const noexcept { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator<(SourceLineInfo const& other) const noexcept { + // We can assume that the same file will usually have the same pointer. + // Thus, if the pointers are the same, there is no point in calling the strcmp + return line < other.line || (line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); + } -std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { + std::ostream& operator<<(std::ostream& os, SourceLineInfo const& info) { #ifndef __GNUG__ -os << info.file << '(' << info.line << ')'; + os << info.file << '(' << info.line << ')'; #else -os << info.file << ':' << info.line; + os << info.file << ':' << info.line; #endif -return os; -} + return os; + } -std::string StreamEndStop::operator+() const { -return std::string(); -} + std::string StreamEndStop::operator+() const { return std::string(); } -NonCopyable::NonCopyable() = default; -NonCopyable::~NonCopyable() = default; + NonCopyable::NonCopyable() = default; + NonCopyable::~NonCopyable() = default; } // end catch_common.cpp @@ -9857,96 +9612,90 @@ NonCopyable::~NonCopyable() = default; namespace Catch { -Config::Config( ConfigData const& data ) -: m_data( data ), -m_stream( openStream() ) -{ -// We need to trim filter specs to avoid trouble with superfluous -// whitespace (esp. important for bdd macros, as those are manually -// aligned with whitespace). + Config::Config(ConfigData const& data) : m_data(data), m_stream(openStream()) { + // We need to trim filter specs to avoid trouble with superfluous + // whitespace (esp. important for bdd macros, as those are manually + // aligned with whitespace). -for (auto& elem : m_data.testsOrTags) { -elem = trim(elem); -} -for (auto& elem : m_data.sectionsToRun) { -elem = trim(elem); -} + for (auto& elem : m_data.testsOrTags) { + elem = trim(elem); + } + for (auto& elem : m_data.sectionsToRun) { + elem = trim(elem); + } -TestSpecParser parser(ITagAliasRegistry::get()); -if (!m_data.testsOrTags.empty()) { -m_hasTestFilters = true; -for (auto const& testOrTags : m_data.testsOrTags) { -parser.parse(testOrTags); -} -} -m_testSpec = parser.testSpec(); -} + TestSpecParser parser(ITagAliasRegistry::get()); + if (!m_data.testsOrTags.empty()) { + m_hasTestFilters = true; + for (auto const& testOrTags : m_data.testsOrTags) { + parser.parse(testOrTags); + } + } + m_testSpec = parser.testSpec(); + } -std::string const& Config::getFilename() const { -return m_data.outputFilename ; -} + std::string const& Config::getFilename() const { return m_data.outputFilename; } -bool Config::listTests() const { return m_data.listTests; } -bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } -bool Config::listTags() const { return m_data.listTags; } -bool Config::listReporters() const { return m_data.listReporters; } + bool Config::listTests() const { return m_data.listTests; } + bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool Config::listTags() const { return m_data.listTags; } + bool Config::listReporters() const { return m_data.listReporters; } -std::string Config::getProcessName() const { return m_data.processName; } -std::string const& Config::getReporterName() const { return m_data.reporterName; } + std::string Config::getProcessName() const { return m_data.processName; } + std::string const& Config::getReporterName() const { return m_data.reporterName; } -std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } -std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } + std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } -TestSpec const& Config::testSpec() const { return m_testSpec; } -bool Config::hasTestFilters() const { return m_hasTestFilters; } + TestSpec const& Config::testSpec() const { return m_testSpec; } + bool Config::hasTestFilters() const { return m_hasTestFilters; } -bool Config::showHelp() const { return m_data.showHelp; } + bool Config::showHelp() const { return m_data.showHelp; } -// IConfig interface -bool Config::allowThrows() const { return !m_data.noThrow; } -std::ostream& Config::stream() const { return m_stream->stream(); } -std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } -bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } -bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } -bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } -ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } -RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } -unsigned int Config::rngSeed() const { return m_data.rngSeed; } -UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } -bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } -int Config::abortAfter() const { return m_data.abortAfter; } -bool Config::showInvisibles() const { return m_data.showInvisibles; } -Verbosity Config::verbosity() const { return m_data.verbosity; } + // IConfig interface + bool Config::allowThrows() const { return !m_data.noThrow; } + std::ostream& Config::stream() const { return m_stream->stream(); } + std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } + bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } + ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } + unsigned int Config::rngSeed() const { return m_data.rngSeed; } + UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } + bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } + int Config::abortAfter() const { return m_data.abortAfter; } + bool Config::showInvisibles() const { return m_data.showInvisibles; } + Verbosity Config::verbosity() const { return m_data.verbosity; } -bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } -int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } -double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } -unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } + bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } + int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } + double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } + unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } -IStream const* Config::openStream() { -return Catch::makeStream(m_data.outputFilename); -} + IStream const* Config::openStream() { return Catch::makeStream(m_data.outputFilename); } } // end namespace Catch // end catch_config.cpp // start catch_console_colour.cpp #if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wexit-time-destructors" #endif // start catch_errno_guard.h namespace Catch { -class ErrnoGuard { -public: -ErrnoGuard(); -~ErrnoGuard(); -private: -int m_oldErrno; -}; + class ErrnoGuard { + public: + ErrnoGuard(); + ~ErrnoGuard(); + + private: + int m_oldErrno; + }; } @@ -9954,179 +9703,171 @@ int m_oldErrno; #include namespace Catch { -namespace { + namespace { -struct IColourImpl { -virtual ~IColourImpl() = default; -virtual void use( Colour::Code _colourCode ) = 0; -}; + struct IColourImpl { + virtual ~IColourImpl() = default; + virtual void use(Colour::Code _colourCode) = 0; + }; -struct NoColourImpl : IColourImpl { -void use( Colour::Code ) {} + struct NoColourImpl : IColourImpl { + void use(Colour::Code) {} -static IColourImpl* instance() { -static NoColourImpl s_instance; -return &s_instance; -} -}; + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; -} // anon namespace + } // anon namespace } // namespace Catch -#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) -# ifdef CATCH_PLATFORM_WINDOWS -# define CATCH_CONFIG_COLOUR_WINDOWS -# else -# define CATCH_CONFIG_COLOUR_ANSI -# endif +#if !defined(CATCH_CONFIG_COLOUR_NONE) && !defined(CATCH_CONFIG_COLOUR_WINDOWS) && !defined(CATCH_CONFIG_COLOUR_ANSI) +#ifdef CATCH_PLATFORM_WINDOWS +#define CATCH_CONFIG_COLOUR_WINDOWS +#else +#define CATCH_CONFIG_COLOUR_ANSI +#endif #endif -#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// +#if defined(CATCH_CONFIG_COLOUR_WINDOWS) ///////////////////////////////////////// namespace Catch { -namespace { + namespace { -class Win32ColourImpl : public IColourImpl { -public: -Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) -{ -CONSOLE_SCREEN_BUFFER_INFO csbiInfo; -GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); -originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); -originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); -} + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE)) { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo); + originalForegroundAttributes = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | + BACKGROUND_BLUE | BACKGROUND_INTENSITY); + originalBackgroundAttributes = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | + FOREGROUND_BLUE | FOREGROUND_INTENSITY); + } -void use( Colour::Code _colourCode ) override { -switch( _colourCode ) { -case Colour::None: return setTextAttribute( originalForegroundAttributes ); -case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); -case Colour::Red: return setTextAttribute( FOREGROUND_RED ); -case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); -case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); -case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); -case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); -case Colour::Grey: return setTextAttribute( 0 ); + void use(Colour::Code _colourCode) override { + switch (_colourCode) { + case Colour::None: return setTextAttribute(originalForegroundAttributes); + case Colour::White: return setTextAttribute(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); + case Colour::Red: return setTextAttribute(FOREGROUND_RED); + case Colour::Green: return setTextAttribute(FOREGROUND_GREEN); + case Colour::Blue: return setTextAttribute(FOREGROUND_BLUE); + case Colour::Cyan: return setTextAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN); + case Colour::Yellow: return setTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN); + case Colour::Grey: return setTextAttribute(0); -case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); -case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); -case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); -case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); -case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::LightGrey: return setTextAttribute(FOREGROUND_INTENSITY); + case Colour::BrightRed: return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_RED); + case Colour::BrightGreen: return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN); + case Colour::BrightWhite: + return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | + FOREGROUND_BLUE); + case Colour::BrightYellow: + return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN); -case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + case Colour::Bright: CATCH_INTERNAL_ERROR("not a colour"); -default: -CATCH_ERROR( "Unknown colour requested" ); -} -} + default: CATCH_ERROR("Unknown colour requested"); + } + } -private: -void setTextAttribute( WORD _textAttribute ) { -SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); -} -HANDLE stdoutHandle; -WORD originalForegroundAttributes; -WORD originalBackgroundAttributes; -}; + private: + void setTextAttribute(WORD _textAttribute) { + SetConsoleTextAttribute(stdoutHandle, _textAttribute | originalBackgroundAttributes); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; -IColourImpl* platformColourInstance() { -static Win32ColourImpl s_instance; + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; -IConfigPtr config = getCurrentContext().getConfig(); -UseColour::YesOrNo colourMode = config -? config->useColour() -: UseColour::Auto; -if( colourMode == UseColour::Auto ) -colourMode = UseColour::Yes; -return colourMode == UseColour::Yes -? &s_instance -: NoColourImpl::instance(); -} + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; + if (colourMode == UseColour::Auto) + colourMode = UseColour::Yes; + return colourMode == UseColour::Yes ? &s_instance : NoColourImpl::instance(); + } -} // end anon namespace + } // end anon namespace } // end namespace Catch -#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// +#elif defined(CATCH_CONFIG_COLOUR_ANSI) ////////////////////////////////////// #include namespace Catch { -namespace { + namespace { -// use POSIX/ ANSI console terminal codes -// Thanks to Adam Strzelecki for original contribution -// (http://github.com/nanoant) -// https://github.com/philsquared/Catch/pull/131 -class PosixColourImpl : public IColourImpl { -public: -void use( Colour::Code _colourCode ) override { -switch( _colourCode ) { -case Colour::None: -case Colour::White: return setColour( "[0m" ); -case Colour::Red: return setColour( "[0;31m" ); -case Colour::Green: return setColour( "[0;32m" ); -case Colour::Blue: return setColour( "[0;34m" ); -case Colour::Cyan: return setColour( "[0;36m" ); -case Colour::Yellow: return setColour( "[0;33m" ); -case Colour::Grey: return setColour( "[1;30m" ); + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + void use(Colour::Code _colourCode) override { + switch (_colourCode) { + case Colour::None: + case Colour::White: return setColour("[0m"); + case Colour::Red: return setColour("[0;31m"); + case Colour::Green: return setColour("[0;32m"); + case Colour::Blue: return setColour("[0;34m"); + case Colour::Cyan: return setColour("[0;36m"); + case Colour::Yellow: return setColour("[0;33m"); + case Colour::Grey: return setColour("[1;30m"); -case Colour::LightGrey: return setColour( "[0;37m" ); -case Colour::BrightRed: return setColour( "[1;31m" ); -case Colour::BrightGreen: return setColour( "[1;32m" ); -case Colour::BrightWhite: return setColour( "[1;37m" ); -case Colour::BrightYellow: return setColour( "[1;33m" ); + case Colour::LightGrey: return setColour("[0;37m"); + case Colour::BrightRed: return setColour("[1;31m"); + case Colour::BrightGreen: return setColour("[1;32m"); + case Colour::BrightWhite: return setColour("[1;37m"); + case Colour::BrightYellow: return setColour("[1;33m"); -case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); -default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); -} -} -static IColourImpl* instance() { -static PosixColourImpl s_instance; -return &s_instance; -} + case Colour::Bright: CATCH_INTERNAL_ERROR("not a colour"); + default: CATCH_INTERNAL_ERROR("Unknown colour requested"); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } -private: -void setColour( const char* _escapeCode ) { -getCurrentContext().getConfig()->stream() -<< '\033' << _escapeCode; -} -}; + private: + void setColour(const char* _escapeCode) { + getCurrentContext().getConfig()->stream() << '\033' << _escapeCode; + } + }; -bool useColourOnPlatform() { -return + bool useColourOnPlatform() { + return #ifdef CATCH_PLATFORM_MAC -!isDebuggerActive() && + !isDebuggerActive() && #endif #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) -isatty(STDOUT_FILENO) + isatty(STDOUT_FILENO) #else -false + false #endif -; -} -IColourImpl* platformColourInstance() { -ErrnoGuard guard; -IConfigPtr config = getCurrentContext().getConfig(); -UseColour::YesOrNo colourMode = config -? config->useColour() -: UseColour::Auto; -if( colourMode == UseColour::Auto ) -colourMode = useColourOnPlatform() -? UseColour::Yes -: UseColour::No; -return colourMode == UseColour::Yes -? PosixColourImpl::instance() -: NoColourImpl::instance(); -} + ; + } + IColourImpl* platformColourInstance() { + ErrnoGuard guard; + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; + if (colourMode == UseColour::Auto) + colourMode = useColourOnPlatform() ? UseColour::Yes : UseColour::No; + return colourMode == UseColour::Yes ? PosixColourImpl::instance() : NoColourImpl::instance(); + } -} // end anon namespace + } // end anon namespace } // end namespace Catch -#else // not Windows or ANSI /////////////////////////////////////////////// +#else // not Windows or ANSI /////////////////////////////////////////////// namespace Catch { -static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } } // end namespace Catch @@ -10134,38 +9875,39 @@ static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); namespace Catch { -Colour::Colour( Code _colourCode ) { use( _colourCode ); } -Colour::Colour( Colour&& rhs ) noexcept { -m_moved = rhs.m_moved; -rhs.m_moved = true; -} -Colour& Colour::operator=( Colour&& rhs ) noexcept { -m_moved = rhs.m_moved; -rhs.m_moved = true; -return *this; -} + Colour::Colour(Code _colourCode) { use(_colourCode); } + Colour::Colour(Colour&& rhs) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + } + Colour& Colour::operator=(Colour&& rhs) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + return *this; + } -Colour::~Colour(){ if( !m_moved ) use( None ); } + Colour::~Colour() { + if (!m_moved) + use(None); + } -void Colour::use( Code _colourCode ) { -static IColourImpl* impl = platformColourInstance(); -// Strictly speaking, this cannot possibly happen. -// However, under some conditions it does happen (see #1626), -// and this change is small enough that we can let practicality -// triumph over purity in this case. -if (impl != NULL) { -impl->use( _colourCode ); -} -} + void Colour::use(Code _colourCode) { + static IColourImpl* impl = platformColourInstance(); + // Strictly speaking, this cannot possibly happen. + // However, under some conditions it does happen (see #1626), + // and this change is small enough that we can let practicality + // triumph over purity in this case. + if (impl != NULL) { + impl->use(_colourCode); + } + } -std::ostream& operator << ( std::ostream& os, Colour const& ) { -return os; -} + std::ostream& operator<<(std::ostream& os, Colour const&) { return os; } } // end namespace Catch #if defined(__clang__) -# pragma clang diagnostic pop +#pragma clang diagnostic pop #endif // end catch_console_colour.cpp @@ -10173,60 +9915,45 @@ return os; namespace Catch { -class Context : public IMutableContext, NonCopyable { + class Context : public IMutableContext, NonCopyable { -public: // IContext -IResultCapture* getResultCapture() override { -return m_resultCapture; -} -IRunner* getRunner() override { -return m_runner; -} + public: // IContext + IResultCapture* getResultCapture() override { return m_resultCapture; } + IRunner* getRunner() override { return m_runner; } -IConfigPtr const& getConfig() const override { -return m_config; -} + IConfigPtr const& getConfig() const override { return m_config; } -~Context() override; + ~Context() override; -public: // IMutableContext -void setResultCapture( IResultCapture* resultCapture ) override { -m_resultCapture = resultCapture; -} -void setRunner( IRunner* runner ) override { -m_runner = runner; -} -void setConfig( IConfigPtr const& config ) override { -m_config = config; -} + public: // IMutableContext + void setResultCapture(IResultCapture* resultCapture) override { m_resultCapture = resultCapture; } + void setRunner(IRunner* runner) override { m_runner = runner; } + void setConfig(IConfigPtr const& config) override { m_config = config; } -friend IMutableContext& getCurrentMutableContext(); + friend IMutableContext& getCurrentMutableContext(); -private: -IConfigPtr m_config; -IRunner* m_runner = nullptr; -IResultCapture* m_resultCapture = nullptr; -}; + private: + IConfigPtr m_config; + IRunner* m_runner = nullptr; + IResultCapture* m_resultCapture = nullptr; + }; -IMutableContext *IMutableContext::currentContext = nullptr; + IMutableContext* IMutableContext::currentContext = nullptr; -void IMutableContext::createContext() -{ -currentContext = new Context(); -} + void IMutableContext::createContext() { currentContext = new Context(); } -void cleanUpContext() { -delete IMutableContext::currentContext; -IMutableContext::currentContext = nullptr; -} -IContext::~IContext() = default; -IMutableContext::~IMutableContext() = default; -Context::~Context() = default; + void cleanUpContext() { + delete IMutableContext::currentContext; + IMutableContext::currentContext = nullptr; + } + IContext::~IContext() = default; + IMutableContext::~IMutableContext() = default; + Context::~Context() = default; -SimplePcg32& rng() { -static SimplePcg32 s_rng; -return s_rng; -} + SimplePcg32& rng() { + static SimplePcg32 s_rng; + return s_rng; + } } // end catch_context.cpp @@ -10237,7 +9964,7 @@ return s_rng; #include namespace Catch { -void writeToDebugConsole( std::string const& text ); + void writeToDebugConsole(std::string const& text); } // end catch_debug_console.h @@ -10245,26 +9972,22 @@ void writeToDebugConsole( std::string const& text ); #include namespace Catch { -void writeToDebugConsole( std::string const& text ) { -__android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() ); -} + void writeToDebugConsole(std::string const& text) { __android_log_write(ANDROID_LOG_DEBUG, "Catch", text.c_str()); } } #elif defined(CATCH_PLATFORM_WINDOWS) namespace Catch { -void writeToDebugConsole( std::string const& text ) { -::OutputDebugStringA( text.c_str() ); -} + void writeToDebugConsole(std::string const& text) { ::OutputDebugStringA(text.c_str()); } } #else namespace Catch { -void writeToDebugConsole( std::string const& text ) { -// !TBD: Need a version for Mac/ XCode and other IDEs -Catch::cout() << text; -} + void writeToDebugConsole(std::string const& text) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } } #endif // Platform @@ -10273,61 +9996,61 @@ Catch::cout() << text; #ifdef CATCH_PLATFORM_MAC -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include #ifdef __apple_build_version__ // These headers will only compile with AppleClang (XCode) // For other compilers (Clang, GCC, ... ) we need to exclude them -# include +#include #endif namespace Catch { #ifdef __apple_build_version__ -// The following function is taken directly from the following technical note: -// https://developer.apple.com/library/archive/qa/qa1361/_index.html + // The following function is taken directly from the following technical note: + // https://developer.apple.com/library/archive/qa/qa1361/_index.html -// Returns true if the current process is being debugged (either -// running under the debugger or has a debugger attached post facto). -bool isDebuggerActive(){ -int mib[4]; -struct kinfo_proc info; -std::size_t size; + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive() { + int mib[4]; + struct kinfo_proc info; + std::size_t size; -// Initialize the flags so that, if sysctl fails for some bizarre -// reason, we get a predictable result. + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. -info.kp_proc.p_flag = 0; + info.kp_proc.p_flag = 0; -// Initialize mib, which tells sysctl the info we want, in this case -// we're looking for information about a specific process ID. + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. -mib[0] = CTL_KERN; -mib[1] = KERN_PROC; -mib[2] = KERN_PROC_PID; -mib[3] = getpid(); + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); -// Call sysctl. + // Call sysctl. -size = sizeof(info); -if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { -Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; -return false; -} + size = sizeof(info); + if (sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } -// We're being debugged if the P_TRACED flag is set. + // We're being debugged if the P_TRACED flag is set. -return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); -} + return ((info.kp_proc.p_flag & P_TRACED) != 0); + } #else -bool isDebuggerActive() { -// We need to find another way to determine this for non-appleclang compilers on macOS -return false; -} + bool isDebuggerActive() { + // We need to find another way to determine this for non-appleclang compilers on macOS + return false; + } #endif } // namespace Catch @@ -10335,49 +10058,45 @@ return false; #include #include -namespace Catch{ -// The standard POSIX way of detecting a debugger is to attempt to -// ptrace() the process, but this needs to be done from a child and not -// this process itself to still allow attaching to this process later -// if wanted, so is rather heavy. Under Linux we have the PID of the -// "debugger" (which doesn't need to be gdb, of course, it could also -// be strace, for example) in /proc/$PID/status, so just get it from -// there instead. -bool isDebuggerActive(){ -// Libstdc++ has a bug, where std::ifstream sets errno to 0 -// This way our users can properly assert over errno values -ErrnoGuard guard; -std::ifstream in("/proc/self/status"); -for( std::string line; std::getline(in, line); ) { -static const int PREFIX_LEN = 11; -if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { -// We're traced if the PID is not 0 and no other PID starts -// with 0 digit, so it's enough to check for just a single -// character. -return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; -} -} +namespace Catch { + // The standard POSIX way of detecting a debugger is to attempt to + // ptrace() the process, but this needs to be done from a child and not + // this process itself to still allow attaching to this process later + // if wanted, so is rather heavy. Under Linux we have the PID of the + // "debugger" (which doesn't need to be gdb, of course, it could also + // be strace, for example) in /proc/$PID/status, so just get it from + // there instead. + bool isDebuggerActive() { + // Libstdc++ has a bug, where std::ifstream sets errno to 0 + // This way our users can properly assert over errno values + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for (std::string line; std::getline(in, line);) { + static const int PREFIX_LEN = 11; + if (line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) { + // We're traced if the PID is not 0 and no other PID starts + // with 0 digit, so it's enough to check for just a single + // character. + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } -return false; -} + return false; + } } // namespace Catch #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { -bool isDebuggerActive() { -return IsDebuggerPresent() != 0; -} + bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { -bool isDebuggerActive() { -return IsDebuggerPresent() != 0; -} + bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #else namespace Catch { -bool isDebuggerActive() { return false; } + bool isDebuggerActive() { return false; } } #endif // Platform // end catch_debugger.cpp @@ -10385,16 +10104,14 @@ bool isDebuggerActive() { return false; } namespace Catch { -ITransientExpression::~ITransientExpression() = default; + ITransientExpression::~ITransientExpression() = default; -void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { -if( lhs.size() + rhs.size() < 40 && -lhs.find('\n') == std::string::npos && -rhs.find('\n') == std::string::npos ) -os << lhs << " " << op << " " << rhs; -else -os << lhs << "\n" << op << "\n" << rhs; -} + void formatReconstructedExpression(std::ostream& os, std::string const& lhs, StringRef op, std::string const& rhs) { + if (lhs.size() + rhs.size() < 40 && lhs.find('\n') == std::string::npos && rhs.find('\n') == std::string::npos) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; + } } // end catch_decomposer.cpp // start catch_enforce.cpp @@ -10403,120 +10120,114 @@ os << lhs << "\n" << op << "\n" << rhs; namespace Catch { #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) -[[noreturn]] -void throw_exception(std::exception const& e) { -Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" -<< "The message was: " << e.what() << '\n'; -std::terminate(); -} + [[noreturn]] void throw_exception(std::exception const& e) { + Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; + std::terminate(); + } #endif -[[noreturn]] -void throw_logic_error(std::string const& msg) { -throw_exception(std::logic_error(msg)); -} + [[noreturn]] void throw_logic_error(std::string const& msg) { throw_exception(std::logic_error(msg)); } -[[noreturn]] -void throw_domain_error(std::string const& msg) { -throw_exception(std::domain_error(msg)); -} + [[noreturn]] void throw_domain_error(std::string const& msg) { throw_exception(std::domain_error(msg)); } -[[noreturn]] -void throw_runtime_error(std::string const& msg) { -throw_exception(std::runtime_error(msg)); -} + [[noreturn]] void throw_runtime_error(std::string const& msg) { throw_exception(std::runtime_error(msg)); } } // namespace Catch; // end catch_enforce.cpp // start catch_enum_values_registry.cpp // start catch_enum_values_registry.h -#include #include +#include namespace Catch { -namespace Detail { + namespace Detail { -std::unique_ptr makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector const& values ); + std::unique_ptr makeEnumInfo(StringRef enumName, StringRef allValueNames, + std::vector const& values); -class EnumValuesRegistry : public IMutableEnumValuesRegistry { + class EnumValuesRegistry : public IMutableEnumValuesRegistry { -std::vector> m_enumInfos; + std::vector> m_enumInfos; -EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector const& values) override; -}; + EnumInfo const& registerEnum(StringRef enumName, StringRef allEnums, + std::vector const& values) override; + }; -std::vector parseEnums( StringRef enums ); + std::vector parseEnums(StringRef enums); -} // Detail + } // Detail } // Catch // end catch_enum_values_registry.h -#include #include +#include namespace Catch { -IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {} + IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {} -namespace Detail { + namespace Detail { -namespace { -// Extracts the actual name part of an enum instance -// In other words, it returns the Blue part of Bikeshed::Colour::Blue -StringRef extractInstanceName(StringRef enumInstance) { -// Find last occurence of ":" -size_t name_start = enumInstance.size(); -while (name_start > 0 && enumInstance[name_start - 1] != ':') { ---name_start; -} -return enumInstance.substr(name_start, enumInstance.size() - name_start); -} -} + namespace { + // Extracts the actual name part of an enum instance + // In other words, it returns the Blue part of Bikeshed::Colour::Blue + StringRef extractInstanceName(StringRef enumInstance) { + // Find last occurence of ":" + size_t name_start = enumInstance.size(); + while (name_start > 0 && enumInstance[name_start - 1] != ':') { + --name_start; + } + return enumInstance.substr(name_start, enumInstance.size() - name_start); + } + } -std::vector parseEnums( StringRef enums ) { -auto enumValues = splitStringRef( enums, ',' ); -std::vector parsed; -parsed.reserve( enumValues.size() ); -for( auto const& enumValue : enumValues ) { -parsed.push_back(trim(extractInstanceName(enumValue))); -} -return parsed; -} + std::vector parseEnums(StringRef enums) { + auto enumValues = splitStringRef(enums, ','); + std::vector parsed; + parsed.reserve(enumValues.size()); + for (auto const& enumValue : enumValues) { + parsed.push_back(trim(extractInstanceName(enumValue))); + } + return parsed; + } -EnumInfo::~EnumInfo() {} + EnumInfo::~EnumInfo() {} -StringRef EnumInfo::lookup( int value ) const { -for( auto const& valueToName : m_values ) { -if( valueToName.first == value ) -return valueToName.second; -} -return "{** unexpected enum value **}"_sr; -} + StringRef EnumInfo::lookup(int value) const { + for (auto const& valueToName : m_values) { + if (valueToName.first == value) + return valueToName.second; + } + return "{** unexpected enum value **}"_sr; + } -std::unique_ptr makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector const& values ) { -std::unique_ptr enumInfo( new EnumInfo ); -enumInfo->m_name = enumName; -enumInfo->m_values.reserve( values.size() ); + std::unique_ptr makeEnumInfo(StringRef enumName, StringRef allValueNames, + std::vector const& values) { + std::unique_ptr enumInfo(new EnumInfo); + enumInfo->m_name = enumName; + enumInfo->m_values.reserve(values.size()); -const auto valueNames = Catch::Detail::parseEnums( allValueNames ); -assert( valueNames.size() == values.size() ); -std::size_t i = 0; -for( auto value : values ) -enumInfo->m_values.push_back({ value, valueNames[i++] }); + const auto valueNames = Catch::Detail::parseEnums(allValueNames); + assert(valueNames.size() == values.size()); + std::size_t i = 0; + for (auto value : values) + enumInfo->m_values.push_back({value, valueNames[i++]}); -return enumInfo; -} + return enumInfo; + } -EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector const& values ) { -m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); -return *m_enumInfos.back(); -} + EnumInfo const& EnumValuesRegistry::registerEnum(StringRef enumName, StringRef allValueNames, + std::vector const& values) { + m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); + return *m_enumInfos.back(); + } -} // Detail + } // Detail } // Catch // end catch_enum_values_registry.cpp @@ -10525,30 +10236,30 @@ return *m_enumInfos.back(); #include namespace Catch { -ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} -ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } + ErrnoGuard::ErrnoGuard() : m_oldErrno(errno) {} + ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } } // end catch_errno_guard.cpp // start catch_exception_translator_registry.cpp // start catch_exception_translator_registry.h -#include -#include #include +#include +#include namespace Catch { -class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { -public: -~ExceptionTranslatorRegistry(); -virtual void registerTranslator( const IExceptionTranslator* translator ); -std::string translateActiveException() const override; -std::string tryTranslators() const; + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry(); + virtual void registerTranslator(const IExceptionTranslator* translator); + std::string translateActiveException() const override; + std::string tryTranslators() const; -private: -std::vector> m_translators; -}; + private: + std::vector> m_translators; + }; } // end catch_exception_translator_registry.h @@ -10558,72 +10269,65 @@ std::vector> m_translators; namespace Catch { -ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { -} + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {} -void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { -m_translators.push_back( std::unique_ptr( translator ) ); -} + void ExceptionTranslatorRegistry::registerTranslator(const IExceptionTranslator* translator) { + m_translators.push_back(std::unique_ptr(translator)); + } #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -std::string ExceptionTranslatorRegistry::translateActiveException() const { -try { + std::string ExceptionTranslatorRegistry::translateActiveException() const { + try { #ifdef __OBJC__ -// In Objective-C try objective-c exceptions first -@try { -return tryTranslators(); -} -@catch (NSException *exception) { -return Catch::Detail::stringify( [exception description] ); -} + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } @catch (NSException* exception) { + return Catch::Detail::stringify([exception description]); + } #else -// Compiling a mixed mode project with MSVC means that CLR -// exceptions will be caught in (...) as well. However, these -// do not fill-in std::current_exception and thus lead to crash -// when attempting rethrow. -// /EHa switch also causes structured exceptions to be caught -// here, but they fill-in current_exception properly, so -// at worst the output should be a little weird, instead of -// causing a crash. -if (std::current_exception() == nullptr) { -return "Non C++ exception. Possibly a CLR exception."; -} -return tryTranslators(); + // Compiling a mixed mode project with MSVC means that CLR + // exceptions will be caught in (...) as well. However, these + // do not fill-in std::current_exception and thus lead to crash + // when attempting rethrow. + // /EHa switch also causes structured exceptions to be caught + // here, but they fill-in current_exception properly, so + // at worst the output should be a little weird, instead of + // causing a crash. + if (std::current_exception() == nullptr) { + return "Non C++ exception. Possibly a CLR exception."; + } + return tryTranslators(); #endif -} -catch( TestFailureException& ) { -std::rethrow_exception(std::current_exception()); -} -catch( std::exception& ex ) { -return ex.what(); -} -catch( std::string& msg ) { -return msg; -} -catch( const char* msg ) { -return msg; -} -catch(...) { -return "Unknown exception"; -} -} + } catch (TestFailureException&) { + std::rethrow_exception(std::current_exception()); + } catch (std::exception& ex) { + return ex.what(); + } catch (std::string& msg) { + return msg; + } catch (const char* msg) { + return msg; + } catch (...) { + return "Unknown exception"; + } + } -std::string ExceptionTranslatorRegistry::tryTranslators() const { -if (m_translators.empty()) { -std::rethrow_exception(std::current_exception()); -} else { -return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); -} -} + std::string ExceptionTranslatorRegistry::tryTranslators() const { + if (m_translators.empty()) { + std::rethrow_exception(std::current_exception()); + } else { + return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); + } + } #else // ^^ Exceptions are enabled // Exceptions are disabled vv -std::string ExceptionTranslatorRegistry::translateActiveException() const { -CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); -} + std::string ExceptionTranslatorRegistry::translateActiveException() const { + CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); + } -std::string ExceptionTranslatorRegistry::tryTranslators() const { -CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); -} + std::string ExceptionTranslatorRegistry::tryTranslators() const { + CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); + } #endif } @@ -10631,162 +10335,157 @@ CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_ // start catch_fatal_condition.cpp #if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif -#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) +#if defined(CATCH_CONFIG_WINDOWS_SEH) || defined(CATCH_CONFIG_POSIX_SIGNALS) namespace { -// Report the error condition -void reportFatal( char const * const message ) { -Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); -} + // Report the error condition + void reportFatal(char const* const message) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition(message); + } } #endif // signals/SEH handling -#if defined( CATCH_CONFIG_WINDOWS_SEH ) +#if defined(CATCH_CONFIG_WINDOWS_SEH) namespace Catch { -struct SignalDefs { DWORD id; const char* name; }; + struct SignalDefs { + DWORD id; + const char* name; + }; -// There is no 1-1 mapping between signals and windows exceptions. -// Windows can easily distinguish between SO and SigSegV, -// but SigInt, SigTerm, etc are handled differently. -static SignalDefs signalDefs[] = { -{ static_cast(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" }, -{ static_cast(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" }, -{ static_cast(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" }, -{ static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, -}; + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + static SignalDefs signalDefs[] = { + {static_cast(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal"}, + {static_cast(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"}, + {static_cast(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal"}, + {static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"}, + }; -LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { -for (auto const& def : signalDefs) { -if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { -reportFatal(def.name); -} -} -// If its not an exception we care about, pass it along. -// This stops us from eating debugger breaks etc. -return EXCEPTION_CONTINUE_SEARCH; -} + LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } -FatalConditionHandler::FatalConditionHandler() { -isSet = true; -// 32k seems enough for Catch to handle stack overflow, -// but the value was found experimentally, so there is no strong guarantee -guaranteeSize = 32 * 1024; -exceptionHandlerHandle = nullptr; -// Register as first handler in current chain -exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); -// Pass in guarantee size to be filled -SetThreadStackGuarantee(&guaranteeSize); -} + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = nullptr; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } -void FatalConditionHandler::reset() { -if (isSet) { -RemoveVectoredExceptionHandler(exceptionHandlerHandle); -SetThreadStackGuarantee(&guaranteeSize); -exceptionHandlerHandle = nullptr; -isSet = false; -} -} + void FatalConditionHandler::reset() { + if (isSet) { + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = nullptr; + isSet = false; + } + } -FatalConditionHandler::~FatalConditionHandler() { -reset(); -} + FatalConditionHandler::~FatalConditionHandler() { reset(); } -bool FatalConditionHandler::isSet = false; -ULONG FatalConditionHandler::guaranteeSize = 0; -PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; } // namespace Catch -#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) +#elif defined(CATCH_CONFIG_POSIX_SIGNALS) namespace Catch { -struct SignalDefs { -int id; -const char* name; -}; + struct SignalDefs { + int id; + const char* name; + }; -// 32kb for the alternate stack seems to be sufficient. However, this value -// is experimentally determined, so that's not guaranteed. -static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; + // 32kb for the alternate stack seems to be sufficient. However, this value + // is experimentally determined, so that's not guaranteed. + static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; -static SignalDefs signalDefs[] = { -{ SIGINT, "SIGINT - Terminal interrupt signal" }, -{ SIGILL, "SIGILL - Illegal instruction signal" }, -{ SIGFPE, "SIGFPE - Floating point error signal" }, -{ SIGSEGV, "SIGSEGV - Segmentation violation signal" }, -{ SIGTERM, "SIGTERM - Termination request signal" }, -{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } -}; + static SignalDefs signalDefs[] = { + {SIGINT, "SIGINT - Terminal interrupt signal"}, {SIGILL, "SIGILL - Illegal instruction signal"}, + {SIGFPE, "SIGFPE - Floating point error signal"}, {SIGSEGV, "SIGSEGV - Segmentation violation signal"}, + {SIGTERM, "SIGTERM - Termination request signal"}, {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}}; -void FatalConditionHandler::handleSignal( int sig ) { -char const * name = ""; -for (auto const& def : signalDefs) { -if (sig == def.id) { -name = def.name; -break; -} -} -reset(); -reportFatal(name); -raise( sig ); -} + void FatalConditionHandler::handleSignal(int sig) { + char const* name = ""; + for (auto const& def : signalDefs) { + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise(sig); + } -FatalConditionHandler::FatalConditionHandler() { -isSet = true; -stack_t sigStack; -sigStack.ss_sp = altStackMem; -sigStack.ss_size = sigStackSize; -sigStack.ss_flags = 0; -sigaltstack(&sigStack, &oldSigStack); -struct sigaction sa = { }; + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = sigStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = {}; -sa.sa_handler = handleSignal; -sa.sa_flags = SA_ONSTACK; -for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { -sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); -} -} + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } -FatalConditionHandler::~FatalConditionHandler() { -reset(); -} + FatalConditionHandler::~FatalConditionHandler() { reset(); } -void FatalConditionHandler::reset() { -if( isSet ) { -// Set signals back to previous values -- hopefully nobody overwrote them in the meantime -for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { -sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); -} -// Return the old stack -sigaltstack(&oldSigStack, nullptr); -isSet = false; -} -} + void FatalConditionHandler::reset() { + if (isSet) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } + } -bool FatalConditionHandler::isSet = false; -struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; -stack_t FatalConditionHandler::oldSigStack = {}; -char FatalConditionHandler::altStackMem[sigStackSize] = {}; + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[sigStackSize] = {}; } // namespace Catch #else namespace Catch { -void FatalConditionHandler::reset() {} + void FatalConditionHandler::reset() {} } #endif // signals/SEH handling #if defined(__GNUC__) -# pragma GCC diagnostic pop +#pragma GCC diagnostic pop #endif // end catch_fatal_condition.cpp // start catch_generators.cpp @@ -10796,47 +10495,45 @@ void FatalConditionHandler::reset() {} namespace Catch { -IGeneratorTracker::~IGeneratorTracker() {} + IGeneratorTracker::~IGeneratorTracker() {} -const char* GeneratorException::what() const noexcept { -return m_msg; -} + const char* GeneratorException::what() const noexcept { return m_msg; } -namespace Generators { + namespace Generators { -GeneratorUntypedBase::~GeneratorUntypedBase() {} + GeneratorUntypedBase::~GeneratorUntypedBase() {} -auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { -return getResultCapture().acquireGeneratorTracker( lineInfo ); -} + auto acquireGeneratorTracker(SourceLineInfo const& lineInfo) -> IGeneratorTracker& { + return getResultCapture().acquireGeneratorTracker(lineInfo); + } -} // namespace Generators + } // namespace Generators } // namespace Catch // end catch_generators.cpp // start catch_interfaces_capture.cpp namespace Catch { -IResultCapture::~IResultCapture() = default; + IResultCapture::~IResultCapture() = default; } // end catch_interfaces_capture.cpp // start catch_interfaces_config.cpp namespace Catch { -IConfig::~IConfig() = default; + IConfig::~IConfig() = default; } // end catch_interfaces_config.cpp // start catch_interfaces_exception.cpp namespace Catch { -IExceptionTranslator::~IExceptionTranslator() = default; -IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; + IExceptionTranslator::~IExceptionTranslator() = default; + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; } // end catch_interfaces_exception.cpp // start catch_interfaces_registry_hub.cpp namespace Catch { -IRegistryHub::~IRegistryHub() = default; -IMutableRegistryHub::~IMutableRegistryHub() = default; + IRegistryHub::~IRegistryHub() = default; + IMutableRegistryHub::~IMutableRegistryHub() = default; } // end catch_interfaces_registry_hub.cpp // start catch_interfaces_reporter.cpp @@ -10845,169 +10542,134 @@ IMutableRegistryHub::~IMutableRegistryHub() = default; namespace Catch { -class ListeningReporter : public IStreamingReporter { -using Reporters = std::vector; -Reporters m_listeners; -IStreamingReporterPtr m_reporter = nullptr; -ReporterPreferences m_preferences; + class ListeningReporter : public IStreamingReporter { + using Reporters = std::vector; + Reporters m_listeners; + IStreamingReporterPtr m_reporter = nullptr; + ReporterPreferences m_preferences; -public: -ListeningReporter(); + public: + ListeningReporter(); -void addListener( IStreamingReporterPtr&& listener ); -void addReporter( IStreamingReporterPtr&& reporter ); + void addListener(IStreamingReporterPtr&& listener); + void addReporter(IStreamingReporterPtr&& reporter); -public: // IStreamingReporter + public: // IStreamingReporter + ReporterPreferences getPreferences() const override; -ReporterPreferences getPreferences() const override; + void noMatchingTestCases(std::string const& spec) override; -void noMatchingTestCases( std::string const& spec ) override; + void reportInvalidArguments(std::string const& arg) override; -void reportInvalidArguments(std::string const&arg) override; - -static std::set getSupportedVerbosities(); + static std::set getSupportedVerbosities(); #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -void benchmarkPreparing(std::string const& name) override; -void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; -void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override; -void benchmarkFailed(std::string const&) override; + void benchmarkPreparing(std::string const& name) override; + void benchmarkStarting(BenchmarkInfo const& benchmarkInfo) override; + void benchmarkEnded(BenchmarkStats<> const& benchmarkStats) override; + void benchmarkFailed(std::string const&) override; #endif // CATCH_CONFIG_ENABLE_BENCHMARKING -void testRunStarting( TestRunInfo const& testRunInfo ) override; -void testGroupStarting( GroupInfo const& groupInfo ) override; -void testCaseStarting( TestCaseInfo const& testInfo ) override; -void sectionStarting( SectionInfo const& sectionInfo ) override; -void assertionStarting( AssertionInfo const& assertionInfo ) override; + void testRunStarting(TestRunInfo const& testRunInfo) override; + void testGroupStarting(GroupInfo const& groupInfo) override; + void testCaseStarting(TestCaseInfo const& testInfo) override; + void sectionStarting(SectionInfo const& sectionInfo) override; + void assertionStarting(AssertionInfo const& assertionInfo) override; -// The return value indicates if the messages buffer should be cleared: -bool assertionEnded( AssertionStats const& assertionStats ) override; -void sectionEnded( SectionStats const& sectionStats ) override; -void testCaseEnded( TestCaseStats const& testCaseStats ) override; -void testGroupEnded( TestGroupStats const& testGroupStats ) override; -void testRunEnded( TestRunStats const& testRunStats ) override; + // The return value indicates if the messages buffer should be cleared: + bool assertionEnded(AssertionStats const& assertionStats) override; + void sectionEnded(SectionStats const& sectionStats) override; + void testCaseEnded(TestCaseStats const& testCaseStats) override; + void testGroupEnded(TestGroupStats const& testGroupStats) override; + void testRunEnded(TestRunStats const& testRunStats) override; -void skipTest( TestCaseInfo const& testInfo ) override; -bool isMulti() const override; - -}; + void skipTest(TestCaseInfo const& testInfo) override; + bool isMulti() const override; + }; } // end namespace Catch // end catch_reporter_listening.h namespace Catch { -ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) -: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + ReporterConfig::ReporterConfig(IConfigPtr const& _fullConfig) + : m_stream(&_fullConfig->stream()), m_fullConfig(_fullConfig) {} -ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) -: m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + ReporterConfig::ReporterConfig(IConfigPtr const& _fullConfig, std::ostream& _stream) + : m_stream(&_stream), m_fullConfig(_fullConfig) {} -std::ostream& ReporterConfig::stream() const { return *m_stream; } -IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } + std::ostream& ReporterConfig::stream() const { return *m_stream; } + IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } -TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} + TestRunInfo::TestRunInfo(std::string const& _name) : name(_name) {} -GroupInfo::GroupInfo( std::string const& _name, -std::size_t _groupIndex, -std::size_t _groupsCount ) -: name( _name ), -groupIndex( _groupIndex ), -groupsCounts( _groupsCount ) -{} + GroupInfo::GroupInfo(std::string const& _name, std::size_t _groupIndex, std::size_t _groupsCount) + : name(_name), groupIndex(_groupIndex), groupsCounts(_groupsCount) {} -AssertionStats::AssertionStats( AssertionResult const& _assertionResult, -std::vector const& _infoMessages, -Totals const& _totals ) -: assertionResult( _assertionResult ), -infoMessages( _infoMessages ), -totals( _totals ) -{ -assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + AssertionStats::AssertionStats(AssertionResult const& _assertionResult, + std::vector const& _infoMessages, Totals const& _totals) + : assertionResult(_assertionResult), infoMessages(_infoMessages), totals(_totals) { + assertionResult.m_resultData.lazyExpression.m_transientExpression = + _assertionResult.m_resultData.lazyExpression.m_transientExpression; -if( assertionResult.hasMessage() ) { -// Copy message into messages list. -// !TBD This should have been done earlier, somewhere -MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); -builder << assertionResult.getMessage(); -builder.m_info.message = builder.m_stream.str(); + if (assertionResult.hasMessage()) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder(assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), + assertionResult.getResultType()); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); -infoMessages.push_back( builder.m_info ); -} -} + infoMessages.push_back(builder.m_info); + } + } -AssertionStats::~AssertionStats() = default; + AssertionStats::~AssertionStats() = default; -SectionStats::SectionStats( SectionInfo const& _sectionInfo, -Counts const& _assertions, -double _durationInSeconds, -bool _missingAssertions ) -: sectionInfo( _sectionInfo ), -assertions( _assertions ), -durationInSeconds( _durationInSeconds ), -missingAssertions( _missingAssertions ) -{} + SectionStats::SectionStats(SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, + bool _missingAssertions) + : sectionInfo(_sectionInfo), assertions(_assertions), durationInSeconds(_durationInSeconds), + missingAssertions(_missingAssertions) {} -SectionStats::~SectionStats() = default; + SectionStats::~SectionStats() = default; -TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, -Totals const& _totals, -std::string const& _stdOut, -std::string const& _stdErr, -bool _aborting ) -: testInfo( _testInfo ), -totals( _totals ), -stdOut( _stdOut ), -stdErr( _stdErr ), -aborting( _aborting ) -{} + TestCaseStats::TestCaseStats(TestCaseInfo const& _testInfo, Totals const& _totals, std::string const& _stdOut, + std::string const& _stdErr, bool _aborting) + : testInfo(_testInfo), totals(_totals), stdOut(_stdOut), stdErr(_stdErr), aborting(_aborting) {} -TestCaseStats::~TestCaseStats() = default; + TestCaseStats::~TestCaseStats() = default; -TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, -Totals const& _totals, -bool _aborting ) -: groupInfo( _groupInfo ), -totals( _totals ), -aborting( _aborting ) -{} + TestGroupStats::TestGroupStats(GroupInfo const& _groupInfo, Totals const& _totals, bool _aborting) + : groupInfo(_groupInfo), totals(_totals), aborting(_aborting) {} -TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) -: groupInfo( _groupInfo ), -aborting( false ) -{} + TestGroupStats::TestGroupStats(GroupInfo const& _groupInfo) : groupInfo(_groupInfo), aborting(false) {} -TestGroupStats::~TestGroupStats() = default; + TestGroupStats::~TestGroupStats() = default; -TestRunStats::TestRunStats( TestRunInfo const& _runInfo, -Totals const& _totals, -bool _aborting ) -: runInfo( _runInfo ), -totals( _totals ), -aborting( _aborting ) -{} + TestRunStats::TestRunStats(TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting) + : runInfo(_runInfo), totals(_totals), aborting(_aborting) {} -TestRunStats::~TestRunStats() = default; + TestRunStats::~TestRunStats() = default; -void IStreamingReporter::fatalErrorEncountered( StringRef ) {} -bool IStreamingReporter::isMulti() const { return false; } + void IStreamingReporter::fatalErrorEncountered(StringRef) {} + bool IStreamingReporter::isMulti() const { return false; } -IReporterFactory::~IReporterFactory() = default; -IReporterRegistry::~IReporterRegistry() = default; + IReporterFactory::~IReporterFactory() = default; + IReporterRegistry::~IReporterRegistry() = default; } // end namespace Catch // end catch_interfaces_reporter.cpp // start catch_interfaces_runner.cpp namespace Catch { -IRunner::~IRunner() = default; + IRunner::~IRunner() = default; } // end catch_interfaces_runner.cpp // start catch_interfaces_testcase.cpp namespace Catch { -ITestInvoker::~ITestInvoker() = default; -ITestCaseRegistry::~ITestCaseRegistry() = default; + ITestInvoker::~ITestInvoker() = default; + ITestCaseRegistry::~ITestCaseRegistry() = default; } // end catch_interfaces_testcase.cpp // start catch_leak_detector.cpp @@ -11017,16 +10679,16 @@ ITestCaseRegistry::~ITestCaseRegistry() = default; namespace Catch { -LeakDetector::LeakDetector() { -int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); -flag |= _CRTDBG_LEAK_CHECK_DF; -flag |= _CRTDBG_ALLOC_MEM_DF; -_CrtSetDbgFlag(flag); -_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); -_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); -// Change this to leaking allocation's number to break there -_CrtSetBreakAlloc(-1); -} + LeakDetector::LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } } #else @@ -11035,9 +10697,7 @@ Catch::LeakDetector::LeakDetector() {} #endif -Catch::LeakDetector::~LeakDetector() { -Catch::cleanUp(); -} +Catch::LeakDetector::~LeakDetector() { Catch::cleanUp(); } // end catch_leak_detector.cpp // start catch_list.cpp @@ -11047,23 +10707,23 @@ Catch::cleanUp(); namespace Catch { -std::size_t listTests( Config const& config ); + std::size_t listTests(Config const& config); -std::size_t listTestsNamesOnly( Config const& config ); + std::size_t listTestsNamesOnly(Config const& config); -struct TagInfo { -void add( std::string const& spelling ); -std::string all() const; + struct TagInfo { + void add(std::string const& spelling); + std::string all() const; -std::set spellings; -std::size_t count = 0; -}; + std::set spellings; + std::size_t count = 0; + }; -std::size_t listTags( Config const& config ); + std::size_t listTags(Config const& config); -std::size_t listReporters(); + std::size_t listReporters(); -Option list( std::shared_ptr const& config ); + Option list(std::shared_ptr const& config); } // end namespace Catch @@ -11071,204 +10731,198 @@ Option list( std::shared_ptr const& config ); // start catch_text.h namespace Catch { -using namespace clara::TextFlow; + using namespace clara::TextFlow; } // end catch_text.h -#include #include #include +#include namespace Catch { -std::size_t listTests( Config const& config ) { -TestSpec testSpec = config.testSpec(); -if( config.hasTestFilters() ) -Catch::cout() << "Matching test cases:\n"; -else { -Catch::cout() << "All available test cases:\n"; -} + std::size_t listTests(Config const& config) { + TestSpec testSpec = config.testSpec(); + if (config.hasTestFilters()) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + } -auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); -for( auto const& testCaseInfo : matchedTestCases ) { -Colour::Code colour = testCaseInfo.isHidden() -? Colour::SecondaryText -: Colour::None; -Colour colourGuard( colour ); + auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config); + for (auto const& testCaseInfo : matchedTestCases) { + Colour::Code colour = testCaseInfo.isHidden() ? Colour::SecondaryText : Colour::None; + Colour colourGuard(colour); -Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; -if( config.verbosity() >= Verbosity::High ) { -Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; -std::string description = testCaseInfo.description; -if( description.empty() ) -description = "(NO DESCRIPTION)"; -Catch::cout() << Column( description ).indent(4) << std::endl; -} -if( !testCaseInfo.tags.empty() ) -Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; -} + Catch::cout() << Column(testCaseInfo.name).initialIndent(2).indent(4) << "\n"; + if (config.verbosity() >= Verbosity::High) { + Catch::cout() << Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << std::endl; + std::string description = testCaseInfo.description; + if (description.empty()) + description = "(NO DESCRIPTION)"; + Catch::cout() << Column(description).indent(4) << std::endl; + } + if (!testCaseInfo.tags.empty()) + Catch::cout() << Column(testCaseInfo.tagsAsString()).indent(6) << "\n"; + } -if( !config.hasTestFilters() ) -Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; -else -Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; -return matchedTestCases.size(); -} + if (!config.hasTestFilters()) + Catch::cout() << pluralise(matchedTestCases.size(), "test case") << '\n' << std::endl; + else + Catch::cout() << pluralise(matchedTestCases.size(), "matching test case") << '\n' << std::endl; + return matchedTestCases.size(); + } -std::size_t listTestsNamesOnly( Config const& config ) { -TestSpec testSpec = config.testSpec(); -std::size_t matchedTests = 0; -std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); -for( auto const& testCaseInfo : matchedTestCases ) { -matchedTests++; -if( startsWith( testCaseInfo.name, '#' ) ) -Catch::cout() << '"' << testCaseInfo.name << '"'; -else -Catch::cout() << testCaseInfo.name; -if ( config.verbosity() >= Verbosity::High ) -Catch::cout() << "\t@" << testCaseInfo.lineInfo; -Catch::cout() << std::endl; -} -return matchedTests; -} + std::size_t listTestsNamesOnly(Config const& config) { + TestSpec testSpec = config.testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config); + for (auto const& testCaseInfo : matchedTestCases) { + matchedTests++; + if (startsWith(testCaseInfo.name, '#')) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if (config.verbosity() >= Verbosity::High) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; + } + return matchedTests; + } -void TagInfo::add( std::string const& spelling ) { -++count; -spellings.insert( spelling ); -} + void TagInfo::add(std::string const& spelling) { + ++count; + spellings.insert(spelling); + } -std::string TagInfo::all() const { -size_t size = 0; -for (auto const& spelling : spellings) { -// Add 2 for the brackes -size += spelling.size() + 2; -} + std::string TagInfo::all() const { + size_t size = 0; + for (auto const& spelling : spellings) { + // Add 2 for the brackes + size += spelling.size() + 2; + } -std::string out; out.reserve(size); -for (auto const& spelling : spellings) { -out += '['; -out += spelling; -out += ']'; -} -return out; -} + std::string out; + out.reserve(size); + for (auto const& spelling : spellings) { + out += '['; + out += spelling; + out += ']'; + } + return out; + } -std::size_t listTags( Config const& config ) { -TestSpec testSpec = config.testSpec(); -if( config.hasTestFilters() ) -Catch::cout() << "Tags for matching test cases:\n"; -else { -Catch::cout() << "All available tags:\n"; -} + std::size_t listTags(Config const& config) { + TestSpec testSpec = config.testSpec(); + if (config.hasTestFilters()) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + } -std::map tagCounts; + std::map tagCounts; -std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); -for( auto const& testCase : matchedTestCases ) { -for( auto const& tagName : testCase.getTestCaseInfo().tags ) { -std::string lcaseTagName = toLower( tagName ); -auto countIt = tagCounts.find( lcaseTagName ); -if( countIt == tagCounts.end() ) -countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; -countIt->second.add( tagName ); -} -} + std::vector matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config); + for (auto const& testCase : matchedTestCases) { + for (auto const& tagName : testCase.getTestCaseInfo().tags) { + std::string lcaseTagName = toLower(tagName); + auto countIt = tagCounts.find(lcaseTagName); + if (countIt == tagCounts.end()) + countIt = tagCounts.insert(std::make_pair(lcaseTagName, TagInfo())).first; + countIt->second.add(tagName); + } + } -for( auto const& tagCount : tagCounts ) { -ReusableStringStream rss; -rss << " " << std::setw(2) << tagCount.second.count << " "; -auto str = rss.str(); -auto wrapper = Column( tagCount.second.all() ) -.initialIndent( 0 ) -.indent( str.size() ) -.width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); -Catch::cout() << str << wrapper << '\n'; -} -Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; -return tagCounts.size(); -} + for (auto const& tagCount : tagCounts) { + ReusableStringStream rss; + rss << " " << std::setw(2) << tagCount.second.count << " "; + auto str = rss.str(); + auto wrapper = Column(tagCount.second.all()) + .initialIndent(0) + .indent(str.size()) + .width(CATCH_CONFIG_CONSOLE_WIDTH - 10); + Catch::cout() << str << wrapper << '\n'; + } + Catch::cout() << pluralise(tagCounts.size(), "tag") << '\n' << std::endl; + return tagCounts.size(); + } -std::size_t listReporters() { -Catch::cout() << "Available reporters:\n"; -IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); -std::size_t maxNameLen = 0; -for( auto const& factoryKvp : factories ) -maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); + std::size_t listReporters() { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + std::size_t maxNameLen = 0; + for (auto const& factoryKvp : factories) + maxNameLen = (std::max)(maxNameLen, factoryKvp.first.size()); -for( auto const& factoryKvp : factories ) { -Catch::cout() -<< Column( factoryKvp.first + ":" ) -.indent(2) -.width( 5+maxNameLen ) -+ Column( factoryKvp.second->getDescription() ) -.initialIndent(0) -.indent(2) -.width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) -<< "\n"; -} -Catch::cout() << std::endl; -return factories.size(); -} + for (auto const& factoryKvp : factories) { + Catch::cout() << Column(factoryKvp.first + ":").indent(2).width(5 + maxNameLen) + + Column(factoryKvp.second->getDescription()) + .initialIndent(0) + .indent(2) + .width(CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8) + << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } -Option list( std::shared_ptr const& config ) { -Option listedCount; -getCurrentMutableContext().setConfig( config ); -if( config->listTests() ) -listedCount = listedCount.valueOr(0) + listTests( *config ); -if( config->listTestNamesOnly() ) -listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); -if( config->listTags() ) -listedCount = listedCount.valueOr(0) + listTags( *config ); -if( config->listReporters() ) -listedCount = listedCount.valueOr(0) + listReporters(); -return listedCount; -} + Option list(std::shared_ptr const& config) { + Option listedCount; + getCurrentMutableContext().setConfig(config); + if (config->listTests()) + listedCount = listedCount.valueOr(0) + listTests(*config); + if (config->listTestNamesOnly()) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly(*config); + if (config->listTags()) + listedCount = listedCount.valueOr(0) + listTags(*config); + if (config->listReporters()) + listedCount = listedCount.valueOr(0) + listReporters(); + return listedCount; + } } // end namespace Catch // end catch_list.cpp // start catch_matchers.cpp namespace Catch { -namespace Matchers { -namespace Impl { + namespace Matchers { + namespace Impl { -std::string MatcherUntypedBase::toString() const { -if( m_cachedToString.empty() ) -m_cachedToString = describe(); -return m_cachedToString; -} + std::string MatcherUntypedBase::toString() const { + if (m_cachedToString.empty()) + m_cachedToString = describe(); + return m_cachedToString; + } -MatcherUntypedBase::~MatcherUntypedBase() = default; + MatcherUntypedBase::~MatcherUntypedBase() = default; -} // namespace Impl -} // namespace Matchers + } // namespace Impl + } // namespace Matchers -using namespace Matchers; -using Matchers::Impl::MatcherBase; + using namespace Matchers; + using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.cpp // start catch_matchers_exception.cpp namespace Catch { -namespace Matchers { -namespace Exception { + namespace Matchers { + namespace Exception { -bool ExceptionMessageMatcher::match(std::exception const& ex) const { -return ex.what() == m_message; -} + bool ExceptionMessageMatcher::match(std::exception const& ex) const { return ex.what() == m_message; } -std::string ExceptionMessageMatcher::describe() const { -return "exception message matches \"" + m_message + "\""; -} + std::string ExceptionMessageMatcher::describe() const { + return "exception message matches \"" + m_message + "\""; + } -} -Exception::ExceptionMessageMatcher Message(std::string const& message) { -return Exception::ExceptionMessageMatcher(message); -} + } + Exception::ExceptionMessageMatcher Message(std::string const& message) { + return Exception::ExceptionMessageMatcher(message); + } -// namespace Exception -} // namespace Matchers + // namespace Exception + } // namespace Matchers } // namespace Catch // end catch_matchers_exception.cpp // start catch_matchers_floating.cpp @@ -11276,8 +10930,8 @@ return Exception::ExceptionMessageMatcher(message); // start catch_polyfills.hpp namespace Catch { -bool isnan(float f); -bool isnan(double d); + bool isnan(float f); + bool isnan(double d); } // end catch_polyfills.hpp @@ -11286,67 +10940,65 @@ bool isnan(double d); #include namespace Catch { -template -std::string to_string(T const& t) { + template std::string to_string(T const& t) { #if defined(CATCH_CONFIG_CPP11_TO_STRING) -return std::to_string(t); + return std::to_string(t); #else -ReusableStringStream rss; -rss << t; -return rss.str(); + ReusableStringStream rss; + rss << t; + return rss.str(); #endif -} + } } // end namespace Catch // end catch_to_string.hpp #include #include -#include #include +#include #include -#include -#include #include #include +#include +#include namespace Catch { -namespace { + namespace { -int32_t convert(float f) { -static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); -int32_t i; -std::memcpy(&i, &f, sizeof(f)); -return i; -} + int32_t convert(float f) { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + int32_t i; + std::memcpy(&i, &f, sizeof(f)); + return i; + } -int64_t convert(double d) { -static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); -int64_t i; -std::memcpy(&i, &d, sizeof(d)); -return i; -} + int64_t convert(double d) { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + int64_t i; + std::memcpy(&i, &d, sizeof(d)); + return i; + } -template -bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { -// Comparison with NaN should always be false. -// This way we can rule it out before getting into the ugly details -if (Catch::isnan(lhs) || Catch::isnan(rhs)) { -return false; -} + template bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (Catch::isnan(lhs) || Catch::isnan(rhs)) { + return false; + } -auto lc = convert(lhs); -auto rc = convert(rhs); + auto lc = convert(lhs); + auto rc = convert(rhs); -if ((lc < 0) != (rc < 0)) { -// Potentially we can have +0 and -0 -return lhs == rhs; -} + if ((lc < 0) != (rc < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } -auto ulpDiff = std::abs(lc - rc); -return static_cast(ulpDiff) <= maxUlpDiff; -} + auto ulpDiff = std::abs(lc - rc); + return static_cast(ulpDiff) <= maxUlpDiff; + } -} //end anonymous namespace + } // end anonymous namespace #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) @@ -11356,17 +11008,11 @@ return static_cast(ulpDiff) <= maxUlpDiff; #pragma clang diagnostic ignored "-Wunused-function" #endif -float nextafter(float x, float y) { -return ::nextafterf(x, y); -} + float nextafter(float x, float y) { return ::nextafterf(x, y); } -double nextafter(double x, double y) { -return ::nextafter(x, y); -} + double nextafter(double x, double y) { return ::nextafter(x, y); } -long double nextafter(long double x, long double y) { -return ::nextafterl(x, y); -} + long double nextafter(long double x, long double y) { return ::nextafterl(x, y); } #if defined(__clang__) #pragma clang diagnostic pop @@ -11374,65 +11020,56 @@ return ::nextafterl(x, y); #endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ -namespace { + namespace { -template -FP step(FP start, FP direction, uint64_t steps) { -for (uint64_t i = 0; i < steps; ++i) { + template FP step(FP start, FP direction, uint64_t steps) { + for (uint64_t i = 0; i < steps; ++i) { #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -start = Catch::nextafter(start, direction); + start = Catch::nextafter(start, direction); #else -start = std::nextafter(start, direction); + start = std::nextafter(start, direction); #endif -} -return start; -} + } + return start; + } -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { -return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); + } -template -void write(std::ostream& out, FloatingPoint num) { -out << std::scientific -<< std::setprecision(std::numeric_limits::max_digits10 - 1) -<< num; -} + template void write(std::ostream& out, FloatingPoint num) { + out << std::scientific << std::setprecision(std::numeric_limits::max_digits10 - 1) << num; + } -} // end anonymous namespace + } // end anonymous namespace -namespace Matchers { -namespace Floating { + namespace Matchers { + namespace Floating { -enum class FloatingPointKind : uint8_t { -Float, -Double -}; + enum class FloatingPointKind : uint8_t { Float, Double }; -WithinAbsMatcher::WithinAbsMatcher(double target, double margin) -:m_target{ target }, m_margin{ margin } { -CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' -<< " Margin has to be non-negative."); -} + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) : m_target{target}, m_margin{margin} { + CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' << " Margin has to be non-negative."); + } -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool WithinAbsMatcher::match(double const& matchee) const { -return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); -} + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool WithinAbsMatcher::match(double const& matchee) const { + return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); + } -std::string WithinAbsMatcher::describe() const { -return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); -} + std::string WithinAbsMatcher::describe() const { + return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + + ::Catch::Detail::stringify(m_target); + } -WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType) -:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { -CATCH_ENFORCE(m_type == FloatingPointKind::Double -|| m_ulps < (std::numeric_limits::max)(), -"Provided ULP is impossibly large for a float comparison."); -} + WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType) + : m_target{target}, m_ulps{ulps}, m_type{baseType} { + CATCH_ENFORCE(m_type == FloatingPointKind::Double || m_ulps < (std::numeric_limits::max)(), + "Provided ULP is impossibly large for a float comparison."); + } #if defined(__clang__) #pragma clang diagnostic push @@ -11440,110 +11077,106 @@ CATCH_ENFORCE(m_type == FloatingPointKind::Double #pragma clang diagnostic ignored "-Wunreachable-code" #endif -bool WithinUlpsMatcher::match(double const& matchee) const { -switch (m_type) { -case FloatingPointKind::Float: -return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); -case FloatingPointKind::Double: -return almostEqualUlps(matchee, m_target, m_ulps); -default: -CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); -} -} + bool WithinUlpsMatcher::match(double const& matchee) const { + switch (m_type) { + case FloatingPointKind::Float: + return almostEqualUlps(static_cast(matchee), static_cast(m_target), + m_ulps); + case FloatingPointKind::Double: return almostEqualUlps(matchee, m_target, m_ulps); + default: CATCH_INTERNAL_ERROR("Unknown FloatingPointKind value"); + } + } #if defined(__clang__) #pragma clang diagnostic pop #endif -std::string WithinUlpsMatcher::describe() const { -std::stringstream ret; + std::string WithinUlpsMatcher::describe() const { + std::stringstream ret; -ret << "is within " << m_ulps << " ULPs of "; + ret << "is within " << m_ulps << " ULPs of "; -if (m_type == FloatingPointKind::Float) { -write(ret, static_cast(m_target)); -ret << 'f'; -} else { -write(ret, m_target); -} + if (m_type == FloatingPointKind::Float) { + write(ret, static_cast(m_target)); + ret << 'f'; + } else { + write(ret, m_target); + } -ret << " (["; -if (m_type == FloatingPointKind::Double) { -write(ret, step(m_target, static_cast(-INFINITY), m_ulps)); -ret << ", "; -write(ret, step(m_target, static_cast( INFINITY), m_ulps)); -} else { -// We have to cast INFINITY to float because of MinGW, see #1782 -write(ret, step(static_cast(m_target), static_cast(-INFINITY), m_ulps)); -ret << ", "; -write(ret, step(static_cast(m_target), static_cast( INFINITY), m_ulps)); -} -ret << "])"; + ret << " (["; + if (m_type == FloatingPointKind::Double) { + write(ret, step(m_target, static_cast(-INFINITY), m_ulps)); + ret << ", "; + write(ret, step(m_target, static_cast(INFINITY), m_ulps)); + } else { + // We have to cast INFINITY to float because of MinGW, see #1782 + write(ret, step(static_cast(m_target), static_cast(-INFINITY), m_ulps)); + ret << ", "; + write(ret, step(static_cast(m_target), static_cast(INFINITY), m_ulps)); + } + ret << "])"; -return ret.str(); -} + return ret.str(); + } -WithinRelMatcher::WithinRelMatcher(double target, double epsilon): -m_target(target), -m_epsilon(epsilon){ -CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense."); -CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense."); -} + WithinRelMatcher::WithinRelMatcher(double target, double epsilon) : m_target(target), m_epsilon(epsilon) { + CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense."); + CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense."); + } -bool WithinRelMatcher::match(double const& matchee) const { -const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); -return marginComparison(matchee, m_target, -std::isinf(relMargin)? 0 : relMargin); -} + bool WithinRelMatcher::match(double const& matchee) const { + const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); + return marginComparison(matchee, m_target, std::isinf(relMargin) ? 0 : relMargin); + } -std::string WithinRelMatcher::describe() const { -Catch::ReusableStringStream sstr; -sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other"; -return sstr.str(); -} + std::string WithinRelMatcher::describe() const { + Catch::ReusableStringStream sstr; + sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other"; + return sstr.str(); + } -}// namespace Floating + } // namespace Floating -Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { -return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); -} + Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); + } -Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { -return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); -} + Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); + } -Floating::WithinAbsMatcher WithinAbs(double target, double margin) { -return Floating::WithinAbsMatcher(target, margin); -} + Floating::WithinAbsMatcher WithinAbs(double target, double margin) { + return Floating::WithinAbsMatcher(target, margin); + } -Floating::WithinRelMatcher WithinRel(double target, double eps) { -return Floating::WithinRelMatcher(target, eps); -} + Floating::WithinRelMatcher WithinRel(double target, double eps) { + return Floating::WithinRelMatcher(target, eps); + } -Floating::WithinRelMatcher WithinRel(double target) { -return Floating::WithinRelMatcher(target, std::numeric_limits::epsilon() * 100); -} + Floating::WithinRelMatcher WithinRel(double target) { + return Floating::WithinRelMatcher(target, std::numeric_limits::epsilon() * 100); + } -Floating::WithinRelMatcher WithinRel(float target, float eps) { -return Floating::WithinRelMatcher(target, eps); -} + Floating::WithinRelMatcher WithinRel(float target, float eps) { + return Floating::WithinRelMatcher(target, eps); + } -Floating::WithinRelMatcher WithinRel(float target) { -return Floating::WithinRelMatcher(target, std::numeric_limits::epsilon() * 100); -} + Floating::WithinRelMatcher WithinRel(float target) { + return Floating::WithinRelMatcher(target, std::numeric_limits::epsilon() * 100); + } -} // namespace Matchers + } // namespace Matchers } // namespace Catch // end catch_matchers_floating.cpp // start catch_matchers_generic.cpp std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { -if (desc.empty()) { -return "matches undescribed predicate"; -} else { -return "matches predicate: \"" + desc + '"'; -} + if (desc.empty()) { + return "matches undescribed predicate"; + } else { + return "matches predicate: \"" + desc + '"'; + } } // end catch_matchers_generic.cpp // start catch_matchers_string.cpp @@ -11551,101 +11184,99 @@ return "matches predicate: \"" + desc + '"'; #include namespace Catch { -namespace Matchers { + namespace Matchers { -namespace StdString { + namespace StdString { -CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) -: m_caseSensitivity( caseSensitivity ), -m_str( adjustString( str ) ) -{} -std::string CasedString::adjustString( std::string const& str ) const { -return m_caseSensitivity == CaseSensitive::No -? toLower( str ) -: str; -} -std::string CasedString::caseSensitivitySuffix() const { -return m_caseSensitivity == CaseSensitive::No -? " (case insensitive)" -: std::string(); -} + CasedString::CasedString(std::string const& str, CaseSensitive::Choice caseSensitivity) + : m_caseSensitivity(caseSensitivity), m_str(adjustString(str)) {} + std::string CasedString::adjustString(std::string const& str) const { + return m_caseSensitivity == CaseSensitive::No ? toLower(str) : str; + } + std::string CasedString::caseSensitivitySuffix() const { + return m_caseSensitivity == CaseSensitive::No ? " (case insensitive)" : std::string(); + } -StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) -: m_comparator( comparator ), -m_operation( operation ) { -} + StringMatcherBase::StringMatcherBase(std::string const& operation, CasedString const& comparator) + : m_comparator(comparator), m_operation(operation) {} -std::string StringMatcherBase::describe() const { -std::string description; -description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + -m_comparator.caseSensitivitySuffix().size()); -description += m_operation; -description += ": \""; -description += m_comparator.m_str; -description += "\""; -description += m_comparator.caseSensitivitySuffix(); -return description; -} + std::string StringMatcherBase::describe() const { + std::string description; + description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + + m_comparator.caseSensitivitySuffix().size()); + description += m_operation; + description += ": \""; + description += m_comparator.m_str; + description += "\""; + description += m_comparator.caseSensitivitySuffix(); + return description; + } -EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} + EqualsMatcher::EqualsMatcher(CasedString const& comparator) : StringMatcherBase("equals", comparator) {} -bool EqualsMatcher::match( std::string const& source ) const { -return m_comparator.adjustString( source ) == m_comparator.m_str; -} + bool EqualsMatcher::match(std::string const& source) const { + return m_comparator.adjustString(source) == m_comparator.m_str; + } -ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} + ContainsMatcher::ContainsMatcher(CasedString const& comparator) + : StringMatcherBase("contains", comparator) {} -bool ContainsMatcher::match( std::string const& source ) const { -return contains( m_comparator.adjustString( source ), m_comparator.m_str ); -} + bool ContainsMatcher::match(std::string const& source) const { + return contains(m_comparator.adjustString(source), m_comparator.m_str); + } -StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} + StartsWithMatcher::StartsWithMatcher(CasedString const& comparator) + : StringMatcherBase("starts with", comparator) {} -bool StartsWithMatcher::match( std::string const& source ) const { -return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); -} + bool StartsWithMatcher::match(std::string const& source) const { + return startsWith(m_comparator.adjustString(source), m_comparator.m_str); + } -EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} + EndsWithMatcher::EndsWithMatcher(CasedString const& comparator) + : StringMatcherBase("ends with", comparator) {} -bool EndsWithMatcher::match( std::string const& source ) const { -return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); -} + bool EndsWithMatcher::match(std::string const& source) const { + return endsWith(m_comparator.adjustString(source), m_comparator.m_str); + } -RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} + RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity) + : m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} -bool RegexMatcher::match(std::string const& matchee) const { -auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway -if (m_caseSensitivity == CaseSensitive::Choice::No) { -flags |= std::regex::icase; -} -auto reg = std::regex(m_regex, flags); -return std::regex_match(matchee, reg); -} + bool RegexMatcher::match(std::string const& matchee) const { + auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway + if (m_caseSensitivity == CaseSensitive::Choice::No) { + flags |= std::regex::icase; + } + auto reg = std::regex(m_regex, flags); + return std::regex_match(matchee, reg); + } -std::string RegexMatcher::describe() const { -return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); -} + std::string RegexMatcher::describe() const { + return "matches " + ::Catch::Detail::stringify(m_regex) + + ((m_caseSensitivity == CaseSensitive::Choice::Yes) ? " case sensitively" + : " case insensitively"); + } -} // namespace StdString + } // namespace StdString -StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { -return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); -} -StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { -return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); -} -StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { -return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); -} -StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { -return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); -} + StdString::EqualsMatcher Equals(std::string const& str, CaseSensitive::Choice caseSensitivity) { + return StdString::EqualsMatcher(StdString::CasedString(str, caseSensitivity)); + } + StdString::ContainsMatcher Contains(std::string const& str, CaseSensitive::Choice caseSensitivity) { + return StdString::ContainsMatcher(StdString::CasedString(str, caseSensitivity)); + } + StdString::EndsWithMatcher EndsWith(std::string const& str, CaseSensitive::Choice caseSensitivity) { + return StdString::EndsWithMatcher(StdString::CasedString(str, caseSensitivity)); + } + StdString::StartsWithMatcher StartsWith(std::string const& str, CaseSensitive::Choice caseSensitivity) { + return StdString::StartsWithMatcher(StdString::CasedString(str, caseSensitivity)); + } -StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { -return StdString::RegexMatcher(regex, caseSensitivity); -} + StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { + return StdString::RegexMatcher(regex, caseSensitivity); + } -} // namespace Matchers + } // namespace Matchers } // namespace Catch // end catch_matchers_string.cpp // start catch_message.cpp @@ -11653,7 +11284,7 @@ return StdString::RegexMatcher(regex, caseSensitivity); // start catch_uncaught_exceptions.h namespace Catch { -bool uncaught_exceptions(); + bool uncaught_exceptions(); } // end namespace Catch // end catch_uncaught_exceptions.h @@ -11662,125 +11293,107 @@ bool uncaught_exceptions(); namespace Catch { -MessageInfo::MessageInfo( StringRef const& _macroName, -SourceLineInfo const& _lineInfo, -ResultWas::OfType _type ) -: macroName( _macroName ), -lineInfo( _lineInfo ), -type( _type ), -sequence( ++globalCount ) -{} + MessageInfo::MessageInfo(StringRef const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type) + : macroName(_macroName), lineInfo(_lineInfo), type(_type), sequence(++globalCount) {} -bool MessageInfo::operator==( MessageInfo const& other ) const { -return sequence == other.sequence; -} + bool MessageInfo::operator==(MessageInfo const& other) const { return sequence == other.sequence; } -bool MessageInfo::operator<( MessageInfo const& other ) const { -return sequence < other.sequence; -} + bool MessageInfo::operator<(MessageInfo const& other) const { return sequence < other.sequence; } -// This may need protecting if threading support is added -unsigned int MessageInfo::globalCount = 0; + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; -//////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// -Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, -SourceLineInfo const& lineInfo, -ResultWas::OfType type ) -:m_info(macroName, lineInfo, type) {} + Catch::MessageBuilder::MessageBuilder(StringRef const& macroName, SourceLineInfo const& lineInfo, + ResultWas::OfType type) + : m_info(macroName, lineInfo, type) {} -//////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// -ScopedMessage::ScopedMessage( MessageBuilder const& builder ) -: m_info( builder.m_info ), m_moved() -{ -m_info.message = builder.m_stream.str(); -getResultCapture().pushScopedMessage( m_info ); -} + ScopedMessage::ScopedMessage(MessageBuilder const& builder) : m_info(builder.m_info), m_moved() { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage(m_info); + } -ScopedMessage::ScopedMessage( ScopedMessage&& old ) -: m_info( old.m_info ), m_moved() -{ -old.m_moved = true; -} + ScopedMessage::ScopedMessage(ScopedMessage&& old) : m_info(old.m_info), m_moved() { old.m_moved = true; } -ScopedMessage::~ScopedMessage() { -if ( !uncaught_exceptions() && !m_moved ){ -getResultCapture().popScopedMessage(m_info); -} -} + ScopedMessage::~ScopedMessage() { + if (!uncaught_exceptions() && !m_moved) { + getResultCapture().popScopedMessage(m_info); + } + } -Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { -auto trimmed = [&] (size_t start, size_t end) { -while (names[start] == ',' || isspace(names[start])) { -++start; -} -while (names[end] == ',' || isspace(names[end])) { ---end; -} -return names.substr(start, end - start + 1); -}; -auto skipq = [&] (size_t start, char quote) { -for (auto i = start + 1; i < names.size() ; ++i) { -if (names[i] == quote) -return i; -if (names[i] == '\\') -++i; -} -CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote"); -}; + Capturer::Capturer(StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, + StringRef names) { + auto trimmed = [&](size_t start, size_t end) { + while (names[start] == ',' || isspace(names[start])) { + ++start; + } + while (names[end] == ',' || isspace(names[end])) { + --end; + } + return names.substr(start, end - start + 1); + }; + auto skipq = [&](size_t start, char quote) { + for (auto i = start + 1; i < names.size(); ++i) { + if (names[i] == quote) + return i; + if (names[i] == '\\') + ++i; + } + CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote"); + }; -size_t start = 0; -std::stack openings; -for (size_t pos = 0; pos < names.size(); ++pos) { -char c = names[pos]; -switch (c) { -case '[': -case '{': -case '(': -// It is basically impossible to disambiguate between -// comparison and start of template args in this context -// case '<': -openings.push(c); -break; -case ']': -case '}': -case ')': -// case '>': -openings.pop(); -break; -case '"': -case '\'': -pos = skipq(pos, c); -break; -case ',': -if (start != pos && openings.size() == 0) { -m_messages.emplace_back(macroName, lineInfo, resultType); -m_messages.back().message = static_cast(trimmed(start, pos)); -m_messages.back().message += " := "; -start = pos; -} -} -} -assert(openings.size() == 0 && "Mismatched openings"); -m_messages.emplace_back(macroName, lineInfo, resultType); -m_messages.back().message = static_cast(trimmed(start, names.size() - 1)); -m_messages.back().message += " := "; -} -Capturer::~Capturer() { -if ( !uncaught_exceptions() ){ -assert( m_captured == m_messages.size() ); -for( size_t i = 0; i < m_captured; ++i ) -m_resultCapture.popScopedMessage( m_messages[i] ); -} -} + size_t start = 0; + std::stack openings; + for (size_t pos = 0; pos < names.size(); ++pos) { + char c = names[pos]; + switch (c) { + case '[': + case '{': + case '(': + // It is basically impossible to disambiguate between + // comparison and start of template args in this context + // case '<': + openings.push(c); + break; + case ']': + case '}': + case ')': + // case '>': + openings.pop(); + break; + case '"': + case '\'': pos = skipq(pos, c); break; + case ',': + if (start != pos && openings.size() == 0) { + m_messages.emplace_back(macroName, lineInfo, resultType); + m_messages.back().message = static_cast(trimmed(start, pos)); + m_messages.back().message += " := "; + start = pos; + } + } + } + assert(openings.size() == 0 && "Mismatched openings"); + m_messages.emplace_back(macroName, lineInfo, resultType); + m_messages.back().message = static_cast(trimmed(start, names.size() - 1)); + m_messages.back().message += " := "; + } + Capturer::~Capturer() { + if (!uncaught_exceptions()) { + assert(m_captured == m_messages.size()); + for (size_t i = 0; i < m_captured; ++i) + m_resultCapture.popScopedMessage(m_messages[i]); + } + } -void Capturer::captureValue( size_t index, std::string const& value ) { -assert( index < m_messages.size() ); -m_messages[index].message += value; -m_resultCapture.pushScopedMessage( m_messages[index] ); -m_captured++; -} + void Capturer::captureValue(size_t index, std::string const& value) { + assert(index < m_messages.size()); + m_messages[index].message += value; + m_resultCapture.pushScopedMessage(m_messages[index]); + m_captured++; + } } // end namespace Catch // end catch_message.cpp @@ -11796,96 +11409,99 @@ m_captured++; namespace Catch { -class RedirectedStream { -std::ostream& m_originalStream; -std::ostream& m_redirectionStream; -std::streambuf* m_prevBuf; + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; -public: -RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); -~RedirectedStream(); -}; + public: + RedirectedStream(std::ostream& originalStream, std::ostream& redirectionStream); + ~RedirectedStream(); + }; -class RedirectedStdOut { -ReusableStringStream m_rss; -RedirectedStream m_cout; -public: -RedirectedStdOut(); -auto str() const -> std::string; -}; + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; -// StdErr has two constituent streams in C++, std::cerr and std::clog -// This means that we need to redirect 2 streams into 1 to keep proper -// order of writes -class RedirectedStdErr { -ReusableStringStream m_rss; -RedirectedStream m_cerr; -RedirectedStream m_clog; -public: -RedirectedStdErr(); -auto str() const -> std::string; -}; + public: + RedirectedStdOut(); + auto str() const -> std::string; + }; -class RedirectedStreams { -public: -RedirectedStreams(RedirectedStreams const&) = delete; -RedirectedStreams& operator=(RedirectedStreams const&) = delete; -RedirectedStreams(RedirectedStreams&&) = delete; -RedirectedStreams& operator=(RedirectedStreams&&) = delete; + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes + class RedirectedStdErr { + ReusableStringStream m_rss; + RedirectedStream m_cerr; + RedirectedStream m_clog; -RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); -~RedirectedStreams(); -private: -std::string& m_redirectedCout; -std::string& m_redirectedCerr; -RedirectedStdOut m_redirectedStdOut; -RedirectedStdErr m_redirectedStdErr; -}; + public: + RedirectedStdErr(); + auto str() const -> std::string; + }; + + class RedirectedStreams { + public: + RedirectedStreams(RedirectedStreams const&) = delete; + RedirectedStreams& operator=(RedirectedStreams const&) = delete; + RedirectedStreams(RedirectedStreams&&) = delete; + RedirectedStreams& operator=(RedirectedStreams&&) = delete; + + RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); + ~RedirectedStreams(); + + private: + std::string& m_redirectedCout; + std::string& m_redirectedCerr; + RedirectedStdOut m_redirectedStdOut; + RedirectedStdErr m_redirectedStdErr; + }; #if defined(CATCH_CONFIG_NEW_CAPTURE) -// Windows's implementation of std::tmpfile is terrible (it tries -// to create a file inside system folder, thus requiring elevated -// privileges for the binary), so we have to use tmpnam(_s) and -// create the file ourselves there. -class TempFile { -public: -TempFile(TempFile const&) = delete; -TempFile& operator=(TempFile const&) = delete; -TempFile(TempFile&&) = delete; -TempFile& operator=(TempFile&&) = delete; + // Windows's implementation of std::tmpfile is terrible (it tries + // to create a file inside system folder, thus requiring elevated + // privileges for the binary), so we have to use tmpnam(_s) and + // create the file ourselves there. + class TempFile { + public: + TempFile(TempFile const&) = delete; + TempFile& operator=(TempFile const&) = delete; + TempFile(TempFile&&) = delete; + TempFile& operator=(TempFile&&) = delete; -TempFile(); -~TempFile(); + TempFile(); + ~TempFile(); -std::FILE* getFile(); -std::string getContents(); + std::FILE* getFile(); + std::string getContents(); -private: -std::FILE* m_file = nullptr; + private: + std::FILE* m_file = nullptr; #if defined(_MSC_VER) -char m_buffer[L_tmpnam] = { 0 }; + char m_buffer[L_tmpnam] = {0}; #endif -}; + }; -class OutputRedirect { -public: -OutputRedirect(OutputRedirect const&) = delete; -OutputRedirect& operator=(OutputRedirect const&) = delete; -OutputRedirect(OutputRedirect&&) = delete; -OutputRedirect& operator=(OutputRedirect&&) = delete; + class OutputRedirect { + public: + OutputRedirect(OutputRedirect const&) = delete; + OutputRedirect& operator=(OutputRedirect const&) = delete; + OutputRedirect(OutputRedirect&&) = delete; + OutputRedirect& operator=(OutputRedirect&&) = delete; -OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); -~OutputRedirect(); + OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); + ~OutputRedirect(); -private: -int m_originalStdout = -1; -int m_originalStderr = -1; -TempFile m_stdoutFile; -TempFile m_stderrFile; -std::string& m_stdoutDest; -std::string& m_stderrDest; -}; + private: + int m_originalStdout = -1; + int m_originalStderr = -1; + TempFile m_stdoutFile; + TempFile m_stderrFile; + std::string& m_stdoutDest; + std::string& m_stderrDest; + }; #endif @@ -11901,121 +11517,107 @@ std::string& m_stderrDest; #if defined(CATCH_CONFIG_NEW_CAPTURE) #if defined(_MSC_VER) -#include //_dup and _dup2 +#include //_dup and _dup2 #define dup _dup #define dup2 _dup2 #define fileno _fileno #else -#include // dup and dup2 +#include // dup and dup2 #endif #endif namespace Catch { -RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) -: m_originalStream( originalStream ), -m_redirectionStream( redirectionStream ), -m_prevBuf( m_originalStream.rdbuf() ) -{ -m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); -} + RedirectedStream::RedirectedStream(std::ostream& originalStream, std::ostream& redirectionStream) + : m_originalStream(originalStream), m_redirectionStream(redirectionStream), + m_prevBuf(m_originalStream.rdbuf()) { + m_originalStream.rdbuf(m_redirectionStream.rdbuf()); + } -RedirectedStream::~RedirectedStream() { -m_originalStream.rdbuf( m_prevBuf ); -} + RedirectedStream::~RedirectedStream() { m_originalStream.rdbuf(m_prevBuf); } -RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} -auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } + RedirectedStdOut::RedirectedStdOut() : m_cout(Catch::cout(), m_rss.get()) {} + auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } -RedirectedStdErr::RedirectedStdErr() -: m_cerr( Catch::cerr(), m_rss.get() ), -m_clog( Catch::clog(), m_rss.get() ) -{} -auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + RedirectedStdErr::RedirectedStdErr() : m_cerr(Catch::cerr(), m_rss.get()), m_clog(Catch::clog(), m_rss.get()) {} + auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } -RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) -: m_redirectedCout(redirectedCout), -m_redirectedCerr(redirectedCerr) -{} + RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) + : m_redirectedCout(redirectedCout), m_redirectedCerr(redirectedCerr) {} -RedirectedStreams::~RedirectedStreams() { -m_redirectedCout += m_redirectedStdOut.str(); -m_redirectedCerr += m_redirectedStdErr.str(); -} + RedirectedStreams::~RedirectedStreams() { + m_redirectedCout += m_redirectedStdOut.str(); + m_redirectedCerr += m_redirectedStdErr.str(); + } #if defined(CATCH_CONFIG_NEW_CAPTURE) #if defined(_MSC_VER) -TempFile::TempFile() { -if (tmpnam_s(m_buffer)) { -CATCH_RUNTIME_ERROR("Could not get a temp filename"); -} -if (fopen_s(&m_file, m_buffer, "w")) { -char buffer[100]; -if (strerror_s(buffer, errno)) { -CATCH_RUNTIME_ERROR("Could not translate errno to a string"); -} -CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); -} -} + TempFile::TempFile() { + if (tmpnam_s(m_buffer)) { + CATCH_RUNTIME_ERROR("Could not get a temp filename"); + } + if (fopen_s(&m_file, m_buffer, "w")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + CATCH_RUNTIME_ERROR("Could not translate errno to a string"); + } + CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); + } + } #else -TempFile::TempFile() { -m_file = std::tmpfile(); -if (!m_file) { -CATCH_RUNTIME_ERROR("Could not create a temp file."); -} -} + TempFile::TempFile() { + m_file = std::tmpfile(); + if (!m_file) { + CATCH_RUNTIME_ERROR("Could not create a temp file."); + } + } #endif -TempFile::~TempFile() { -// TBD: What to do about errors here? -std::fclose(m_file); + TempFile::~TempFile() { + // TBD: What to do about errors here? + std::fclose(m_file); // We manually create the file on Windows only, on Linux // it will be autodeleted #if defined(_MSC_VER) -std::remove(m_buffer); + std::remove(m_buffer); #endif -} + } -FILE* TempFile::getFile() { -return m_file; -} + FILE* TempFile::getFile() { return m_file; } -std::string TempFile::getContents() { -std::stringstream sstr; -char buffer[100] = {}; -std::rewind(m_file); -while (std::fgets(buffer, sizeof(buffer), m_file)) { -sstr << buffer; -} -return sstr.str(); -} + std::string TempFile::getContents() { + std::stringstream sstr; + char buffer[100] = {}; + std::rewind(m_file); + while (std::fgets(buffer, sizeof(buffer), m_file)) { + sstr << buffer; + } + return sstr.str(); + } -OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : -m_originalStdout(dup(1)), -m_originalStderr(dup(2)), -m_stdoutDest(stdout_dest), -m_stderrDest(stderr_dest) { -dup2(fileno(m_stdoutFile.getFile()), 1); -dup2(fileno(m_stderrFile.getFile()), 2); -} + OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) + : m_originalStdout(dup(1)), m_originalStderr(dup(2)), m_stdoutDest(stdout_dest), m_stderrDest(stderr_dest) { + dup2(fileno(m_stdoutFile.getFile()), 1); + dup2(fileno(m_stderrFile.getFile()), 2); + } -OutputRedirect::~OutputRedirect() { -Catch::cout() << std::flush; -fflush(stdout); -// Since we support overriding these streams, we flush cerr -// even though std::cerr is unbuffered -Catch::cerr() << std::flush; -Catch::clog() << std::flush; -fflush(stderr); + OutputRedirect::~OutputRedirect() { + Catch::cout() << std::flush; + fflush(stdout); + // Since we support overriding these streams, we flush cerr + // even though std::cerr is unbuffered + Catch::cerr() << std::flush; + Catch::clog() << std::flush; + fflush(stderr); -dup2(m_originalStdout, 1); -dup2(m_originalStderr, 2); + dup2(m_originalStdout, 1); + dup2(m_originalStderr, 2); -m_stdoutDest += m_stdoutFile.getContents(); -m_stderrDest += m_stderrFile.getContents(); -} + m_stdoutDest += m_stdoutFile.getContents(); + m_stderrDest += m_stderrFile.getContents(); + } #endif // CATCH_CONFIG_NEW_CAPTURE @@ -12036,20 +11638,12 @@ m_stderrDest += m_stderrFile.getContents(); namespace Catch { #if !defined(CATCH_CONFIG_POLYFILL_ISNAN) -bool isnan(float f) { -return std::isnan(f); -} -bool isnan(double d) { -return std::isnan(d); -} + bool isnan(float f) { return std::isnan(f); } + bool isnan(double d) { return std::isnan(d); } #else -// For now we only use this for embarcadero -bool isnan(float f) { -return std::_isnan(f); -} -bool isnan(double d) { -return std::_isnan(d); -} + // For now we only use this for embarcadero + bool isnan(float f) { return std::_isnan(f); } + bool isnan(double d) { return std::_isnan(d); } #endif } // end namespace Catch @@ -12058,118 +11652,114 @@ return std::_isnan(d); namespace Catch { -namespace { + namespace { #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable:4146) // we negate uint32 during the rotate +#pragma warning(disable : 4146) // we negate uint32 during the rotate #endif -// Safe rotr implementation thanks to John Regehr -uint32_t rotate_right(uint32_t val, uint32_t count) { -const uint32_t mask = 31; -count &= mask; -return (val >> count) | (val << (-count & mask)); -} + // Safe rotr implementation thanks to John Regehr + uint32_t rotate_right(uint32_t val, uint32_t count) { + const uint32_t mask = 31; + count &= mask; + return (val >> count) | (val << (-count & mask)); + } #if defined(_MSC_VER) #pragma warning(pop) #endif -} + } -SimplePcg32::SimplePcg32(result_type seed_) { -seed(seed_); -} + SimplePcg32::SimplePcg32(result_type seed_) { seed(seed_); } -void SimplePcg32::seed(result_type seed_) { -m_state = 0; -(*this)(); -m_state += seed_; -(*this)(); -} + void SimplePcg32::seed(result_type seed_) { + m_state = 0; + (*this)(); + m_state += seed_; + (*this)(); + } -void SimplePcg32::discard(uint64_t skip) { -// We could implement this to run in O(log n) steps, but this -// should suffice for our use case. -for (uint64_t s = 0; s < skip; ++s) { -static_cast((*this)()); -} -} + void SimplePcg32::discard(uint64_t skip) { + // We could implement this to run in O(log n) steps, but this + // should suffice for our use case. + for (uint64_t s = 0; s < skip; ++s) { + static_cast((*this)()); + } + } -SimplePcg32::result_type SimplePcg32::operator()() { -// prepare the output value -const uint32_t xorshifted = static_cast(((m_state >> 18u) ^ m_state) >> 27u); -const auto output = rotate_right(xorshifted, m_state >> 59u); + SimplePcg32::result_type SimplePcg32::operator()() { + // prepare the output value + const uint32_t xorshifted = static_cast(((m_state >> 18u) ^ m_state) >> 27u); + const auto output = rotate_right(xorshifted, m_state >> 59u); -// advance state -m_state = m_state * 6364136223846793005ULL + s_inc; + // advance state + m_state = m_state * 6364136223846793005ULL + s_inc; -return output; -} + return output; + } -bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { -return lhs.m_state == rhs.m_state; -} + bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { return lhs.m_state == rhs.m_state; } -bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { -return lhs.m_state != rhs.m_state; -} + bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { return lhs.m_state != rhs.m_state; } } // end catch_random_number_generator.cpp // start catch_registry_hub.cpp // start catch_test_case_registry_impl.h -#include -#include #include #include +#include +#include namespace Catch { -class TestCase; -struct IConfig; + class TestCase; + struct IConfig; -std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); + std::vector sortTests(IConfig const& config, std::vector const& unsortedTestCases); -bool isThrowSafe( TestCase const& testCase, IConfig const& config ); -bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + bool isThrowSafe(TestCase const& testCase, IConfig const& config); + bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config); -void enforceNoDuplicateTestCases( std::vector const& functions ); + void enforceNoDuplicateTestCases(std::vector const& functions); -std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); -std::vector const& getAllTestCasesSorted( IConfig const& config ); + std::vector filterTests(std::vector const& testCases, TestSpec const& testSpec, + IConfig const& config); + std::vector const& getAllTestCasesSorted(IConfig const& config); -class TestRegistry : public ITestCaseRegistry { -public: -virtual ~TestRegistry() = default; + class TestRegistry : public ITestCaseRegistry { + public: + virtual ~TestRegistry() = default; -virtual void registerTest( TestCase const& testCase ); + virtual void registerTest(TestCase const& testCase); -std::vector const& getAllTests() const override; -std::vector const& getAllTestsSorted( IConfig const& config ) const override; + std::vector const& getAllTests() const override; + std::vector const& getAllTestsSorted(IConfig const& config) const override; -private: -std::vector m_functions; -mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; -mutable std::vector m_sortedFunctions; -std::size_t m_unnamedCount = 0; -std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised -}; + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; + mutable std::vector m_sortedFunctions; + std::size_t m_unnamedCount = 0; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; -/////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// -class TestInvokerAsFunction : public ITestInvoker { -void(*m_testAsFunction)(); -public: -TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; + class TestInvokerAsFunction : public ITestInvoker { + void (*m_testAsFunction)(); -void invoke() const override; -}; + public: + TestInvokerAsFunction(void (*testAsFunction)()) noexcept; -std::string extractClassName( StringRef const& classOrQualifiedMethodName ); + void invoke() const override; + }; -/////////////////////////////////////////////////////////////////////////// + std::string extractClassName(StringRef const& classOrQualifiedMethodName); + + /////////////////////////////////////////////////////////////////////////// } // end namespace Catch @@ -12180,24 +11770,23 @@ std::string extractClassName( StringRef const& classOrQualifiedMethodName ); namespace Catch { -class ReporterRegistry : public IReporterRegistry { + class ReporterRegistry : public IReporterRegistry { -public: + public: + ~ReporterRegistry() override; -~ReporterRegistry() override; + IStreamingReporterPtr create(std::string const& name, IConfigPtr const& config) const override; -IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; + void registerReporter(std::string const& name, IReporterFactoryPtr const& factory); + void registerListener(IReporterFactoryPtr const& factory); -void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); -void registerListener( IReporterFactoryPtr const& factory ); + FactoryMap const& getFactories() const override; + Listeners const& getListeners() const override; -FactoryMap const& getFactories() const override; -Listeners const& getListeners() const override; - -private: -FactoryMap m_factories; -Listeners m_listeners; -}; + private: + FactoryMap m_factories; + Listeners m_listeners; + }; } // end catch_reporter_registry.h @@ -12209,12 +11798,12 @@ Listeners m_listeners; namespace Catch { -struct TagAlias { -TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); + struct TagAlias { + TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); -std::string tag; -SourceLineInfo lineInfo; -}; + std::string tag; + SourceLineInfo lineInfo; + }; } // end namespace Catch @@ -12223,34 +11812,35 @@ SourceLineInfo lineInfo; namespace Catch { -class TagAliasRegistry : public ITagAliasRegistry { -public: -~TagAliasRegistry() override; -TagAlias const* find( std::string const& alias ) const override; -std::string expandAliases( std::string const& unexpandedTestSpec ) const override; -void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + class TagAliasRegistry : public ITagAliasRegistry { + public: + ~TagAliasRegistry() override; + TagAlias const* find(std::string const& alias) const override; + std::string expandAliases(std::string const& unexpandedTestSpec) const override; + void add(std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo); -private: -std::map m_registry; -}; + private: + std::map m_registry; + }; } // end namespace Catch // end catch_tag_alias_registry.h // start catch_startup_exception_registry.h -#include #include +#include namespace Catch { -class StartupExceptionRegistry { -public: -void add(std::exception_ptr const& exception) noexcept; -std::vector const& getExceptions() const noexcept; -private: -std::vector m_exceptions; -}; + class StartupExceptionRegistry { + public: + void add(std::exception_ptr const& exception) noexcept; + std::vector const& getExceptions() const noexcept; + + private: + std::vector m_exceptions; + }; } // end namespace Catch @@ -12259,110 +11849,88 @@ std::vector m_exceptions; namespace Catch { -struct ISingleton { -virtual ~ISingleton(); -}; + struct ISingleton { + virtual ~ISingleton(); + }; -void addSingleton( ISingleton* singleton ); -void cleanupSingletons(); + void addSingleton(ISingleton* singleton); + void cleanupSingletons(); -template -class Singleton : SingletonImplT, public ISingleton { + template + class Singleton : SingletonImplT, public ISingleton { -static auto getInternal() -> Singleton* { -static Singleton* s_instance = nullptr; -if( !s_instance ) { -s_instance = new Singleton; -addSingleton( s_instance ); -} -return s_instance; -} + static auto getInternal() -> Singleton* { + static Singleton* s_instance = nullptr; + if (!s_instance) { + s_instance = new Singleton; + addSingleton(s_instance); + } + return s_instance; + } -public: -static auto get() -> InterfaceT const& { -return *getInternal(); -} -static auto getMutable() -> MutableInterfaceT& { -return *getInternal(); -} -}; + public: + static auto get() -> InterfaceT const& { return *getInternal(); } + static auto getMutable() -> MutableInterfaceT& { return *getInternal(); } + }; } // namespace Catch // end catch_singletons.hpp namespace Catch { -namespace { + namespace { -class RegistryHub : public IRegistryHub, public IMutableRegistryHub, -private NonCopyable { + class RegistryHub : public IRegistryHub, public IMutableRegistryHub, private NonCopyable { -public: // IRegistryHub -RegistryHub() = default; -IReporterRegistry const& getReporterRegistry() const override { -return m_reporterRegistry; -} -ITestCaseRegistry const& getTestCaseRegistry() const override { -return m_testCaseRegistry; -} -IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { -return m_exceptionTranslatorRegistry; -} -ITagAliasRegistry const& getTagAliasRegistry() const override { -return m_tagAliasRegistry; -} -StartupExceptionRegistry const& getStartupExceptionRegistry() const override { -return m_exceptionRegistry; -} + public: // IRegistryHub + RegistryHub() = default; + IReporterRegistry const& getReporterRegistry() const override { return m_reporterRegistry; } + ITestCaseRegistry const& getTestCaseRegistry() const override { return m_testCaseRegistry; } + IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { + return m_exceptionTranslatorRegistry; + } + ITagAliasRegistry const& getTagAliasRegistry() const override { return m_tagAliasRegistry; } + StartupExceptionRegistry const& getStartupExceptionRegistry() const override { return m_exceptionRegistry; } -public: // IMutableRegistryHub -void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { -m_reporterRegistry.registerReporter( name, factory ); -} -void registerListener( IReporterFactoryPtr const& factory ) override { -m_reporterRegistry.registerListener( factory ); -} -void registerTest( TestCase const& testInfo ) override { -m_testCaseRegistry.registerTest( testInfo ); -} -void registerTranslator( const IExceptionTranslator* translator ) override { -m_exceptionTranslatorRegistry.registerTranslator( translator ); -} -void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { -m_tagAliasRegistry.add( alias, tag, lineInfo ); -} -void registerStartupException() noexcept override { -m_exceptionRegistry.add(std::current_exception()); -} -IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { -return m_enumValuesRegistry; -} + public: // IMutableRegistryHub + void registerReporter(std::string const& name, IReporterFactoryPtr const& factory) override { + m_reporterRegistry.registerReporter(name, factory); + } + void registerListener(IReporterFactoryPtr const& factory) override { + m_reporterRegistry.registerListener(factory); + } + void registerTest(TestCase const& testInfo) override { m_testCaseRegistry.registerTest(testInfo); } + void registerTranslator(const IExceptionTranslator* translator) override { + m_exceptionTranslatorRegistry.registerTranslator(translator); + } + void registerTagAlias(std::string const& alias, std::string const& tag, + SourceLineInfo const& lineInfo) override { + m_tagAliasRegistry.add(alias, tag, lineInfo); + } + void registerStartupException() noexcept override { m_exceptionRegistry.add(std::current_exception()); } + IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { return m_enumValuesRegistry; } -private: -TestRegistry m_testCaseRegistry; -ReporterRegistry m_reporterRegistry; -ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; -TagAliasRegistry m_tagAliasRegistry; -StartupExceptionRegistry m_exceptionRegistry; -Detail::EnumValuesRegistry m_enumValuesRegistry; -}; -} + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; + StartupExceptionRegistry m_exceptionRegistry; + Detail::EnumValuesRegistry m_enumValuesRegistry; + }; + } -using RegistryHubSingleton = Singleton; + using RegistryHubSingleton = Singleton; -IRegistryHub const& getRegistryHub() { -return RegistryHubSingleton::get(); -} -IMutableRegistryHub& getMutableRegistryHub() { -return RegistryHubSingleton::getMutable(); -} -void cleanUp() { -cleanupSingletons(); -cleanUpContext(); -} -std::string translateActiveException() { -return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); -} + IRegistryHub const& getRegistryHub() { return RegistryHubSingleton::get(); } + IMutableRegistryHub& getMutableRegistryHub() { return RegistryHubSingleton::getMutable(); } + void cleanUp() { + cleanupSingletons(); + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } } // end namespace Catch // end catch_registry_hub.cpp @@ -12370,28 +11938,22 @@ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveExceptio namespace Catch { -ReporterRegistry::~ReporterRegistry() = default; + ReporterRegistry::~ReporterRegistry() = default; -IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { -auto it = m_factories.find( name ); -if( it == m_factories.end() ) -return nullptr; -return it->second->create( ReporterConfig( config ) ); -} + IStreamingReporterPtr ReporterRegistry::create(std::string const& name, IConfigPtr const& config) const { + auto it = m_factories.find(name); + if (it == m_factories.end()) + return nullptr; + return it->second->create(ReporterConfig(config)); + } -void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { -m_factories.emplace(name, factory); -} -void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { -m_listeners.push_back( factory ); -} + void ReporterRegistry::registerReporter(std::string const& name, IReporterFactoryPtr const& factory) { + m_factories.emplace(name, factory); + } + void ReporterRegistry::registerListener(IReporterFactoryPtr const& factory) { m_listeners.push_back(factory); } -IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { -return m_factories; -} -IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { -return m_listeners; -} + IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { return m_factories; } + IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { return m_listeners; } } // end catch_reporter_registry.cpp @@ -12399,533 +11961,465 @@ return m_listeners; namespace Catch { -bool isOk( ResultWas::OfType resultType ) { -return ( resultType & ResultWas::FailureBit ) == 0; -} -bool isJustInfo( int flags ) { -return flags == ResultWas::Info; -} + bool isOk(ResultWas::OfType resultType) { return (resultType & ResultWas::FailureBit) == 0; } + bool isJustInfo(int flags) { return flags == ResultWas::Info; } -ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { -return static_cast( static_cast( lhs ) | static_cast( rhs ) ); -} + ResultDisposition::Flags operator|(ResultDisposition::Flags lhs, ResultDisposition::Flags rhs) { + return static_cast(static_cast(lhs) | static_cast(rhs)); + } -bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } -bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + bool shouldContinueOnFailure(int flags) { return (flags & ResultDisposition::ContinueOnFailure) != 0; } + bool shouldSuppressFailure(int flags) { return (flags & ResultDisposition::SuppressFail) != 0; } } // end namespace Catch // end catch_result_type.cpp // start catch_run_context.cpp -#include #include +#include #include namespace Catch { -namespace Generators { -struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { -GeneratorBasePtr m_generator; + namespace Generators { + struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { + GeneratorBasePtr m_generator; -GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) -: TrackerBase( nameAndLocation, ctx, parent ) -{} -~GeneratorTracker(); + GeneratorTracker(TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, + ITracker* parent) + : TrackerBase(nameAndLocation, ctx, parent) {} + ~GeneratorTracker(); -static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { -std::shared_ptr tracker; + static GeneratorTracker& acquire(TrackerContext& ctx, + TestCaseTracking::NameAndLocation const& nameAndLocation) { + std::shared_ptr tracker; -ITracker& currentTracker = ctx.currentTracker(); -if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { -assert( childTracker ); -assert( childTracker->isGeneratorTracker() ); -tracker = std::static_pointer_cast( childTracker ); -} -else { -tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker ); -currentTracker.addChild( tracker ); -} + ITracker& currentTracker = ctx.currentTracker(); + if (TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild(nameAndLocation)) { + assert(childTracker); + assert(childTracker->isGeneratorTracker()); + tracker = std::static_pointer_cast(childTracker); + } else { + tracker = std::make_shared(nameAndLocation, ctx, ¤tTracker); + currentTracker.addChild(tracker); + } -if( !ctx.completedCycle() && !tracker->isComplete() ) { -tracker->open(); -} + if (!ctx.completedCycle() && !tracker->isComplete()) { + tracker->open(); + } -return *tracker; -} + return *tracker; + } -// TrackerBase interface -bool isGeneratorTracker() const override { return true; } -auto hasGenerator() const -> bool override { -return !!m_generator; -} -void close() override { -TrackerBase::close(); -// Generator interface only finds out if it has another item on atual move -if (m_runState == CompletedSuccessfully && m_generator->next()) { -m_children.clear(); -m_runState = Executing; -} -} + // TrackerBase interface + bool isGeneratorTracker() const override { return true; } + auto hasGenerator() const -> bool override { return !!m_generator; } + void close() override { + TrackerBase::close(); + // Generator interface only finds out if it has another item on atual move + if (m_runState == CompletedSuccessfully && m_generator->next()) { + m_children.clear(); + m_runState = Executing; + } + } -// IGeneratorTracker interface -auto getGenerator() const -> GeneratorBasePtr const& override { -return m_generator; -} -void setGenerator( GeneratorBasePtr&& generator ) override { -m_generator = std::move( generator ); -} -}; -GeneratorTracker::~GeneratorTracker() {} -} + // IGeneratorTracker interface + auto getGenerator() const -> GeneratorBasePtr const& override { return m_generator; } + void setGenerator(GeneratorBasePtr&& generator) override { m_generator = std::move(generator); } + }; + GeneratorTracker::~GeneratorTracker() {} + } -RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) -: m_runInfo(_config->name()), -m_context(getCurrentMutableContext()), -m_config(_config), -m_reporter(std::move(reporter)), -m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, -m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) -{ -m_context.setRunner(this); -m_context.setConfig(m_config); -m_context.setResultCapture(this); -m_reporter->testRunStarting(m_runInfo); -} + RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) + : m_runInfo(_config->name()), m_context(getCurrentMutableContext()), m_config(_config), + m_reporter(std::move(reporter)), m_lastAssertionInfo{StringRef(), SourceLineInfo("", 0), StringRef(), + ResultDisposition::Normal}, + m_includeSuccessfulResults(m_config->includeSuccessfulResults() || + m_reporter->getPreferences().shouldReportAllAssertions) { + m_context.setRunner(this); + m_context.setConfig(m_config); + m_context.setResultCapture(this); + m_reporter->testRunStarting(m_runInfo); + } -RunContext::~RunContext() { -m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); -} + RunContext::~RunContext() { m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); } -void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { -m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); -} + void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); + } -void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { -m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); -} + void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, + std::size_t groupsCount) { + m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); + } -Totals RunContext::runTest(TestCase const& testCase) { -Totals prevTotals = m_totals; + Totals RunContext::runTest(TestCase const& testCase) { + Totals prevTotals = m_totals; -std::string redirectedCout; -std::string redirectedCerr; + std::string redirectedCout; + std::string redirectedCerr; -auto const& testInfo = testCase.getTestCaseInfo(); + auto const& testInfo = testCase.getTestCaseInfo(); -m_reporter->testCaseStarting(testInfo); + m_reporter->testCaseStarting(testInfo); -m_activeTestCase = &testCase; + m_activeTestCase = &testCase; -ITracker& rootTracker = m_trackerContext.startRun(); -assert(rootTracker.isSectionTracker()); -static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); -do { -m_trackerContext.startCycle(); -m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); -runCurrentTest(redirectedCout, redirectedCerr); -} while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); + ITracker& rootTracker = m_trackerContext.startRun(); + assert(rootTracker.isSectionTracker()); + static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( + m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + runCurrentTest(redirectedCout, redirectedCerr); + } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); -Totals deltaTotals = m_totals.delta(prevTotals); -if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { -deltaTotals.assertions.failed++; -deltaTotals.testCases.passed--; -deltaTotals.testCases.failed++; -} -m_totals.testCases += deltaTotals.testCases; -m_reporter->testCaseEnded(TestCaseStats(testInfo, -deltaTotals, -redirectedCout, -redirectedCerr, -aborting())); + Totals deltaTotals = m_totals.delta(prevTotals); + if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded(TestCaseStats(testInfo, deltaTotals, redirectedCout, redirectedCerr, aborting())); -m_activeTestCase = nullptr; -m_testCaseTracker = nullptr; + m_activeTestCase = nullptr; + m_testCaseTracker = nullptr; -return deltaTotals; -} + return deltaTotals; + } -IConfigPtr RunContext::config() const { -return m_config; -} + IConfigPtr RunContext::config() const { return m_config; } -IStreamingReporter& RunContext::reporter() const { -return *m_reporter; -} + IStreamingReporter& RunContext::reporter() const { return *m_reporter; } -void RunContext::assertionEnded(AssertionResult const & result) { -if (result.getResultType() == ResultWas::Ok) { -m_totals.assertions.passed++; -m_lastAssertionPassed = true; -} else if (!result.isOk()) { -m_lastAssertionPassed = false; -if( m_activeTestCase->getTestCaseInfo().okToFail() ) -m_totals.assertions.failedButOk++; -else -m_totals.assertions.failed++; -} -else { -m_lastAssertionPassed = true; -} + void RunContext::assertionEnded(AssertionResult const& result) { + if (result.getResultType() == ResultWas::Ok) { + m_totals.assertions.passed++; + m_lastAssertionPassed = true; + } else if (!result.isOk()) { + m_lastAssertionPassed = false; + if (m_activeTestCase->getTestCaseInfo().okToFail()) + m_totals.assertions.failedButOk++; + else + m_totals.assertions.failed++; + } else { + m_lastAssertionPassed = true; + } -// We have no use for the return value (whether messages should be cleared), because messages were made scoped -// and should be let to clear themselves out. -static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); -if (result.getResultType() != ResultWas::Warning) -m_messageScopes.clear(); + if (result.getResultType() != ResultWas::Warning) + m_messageScopes.clear(); -// Reset working state -resetAssertionInfo(); -m_lastResult = result; -} -void RunContext::resetAssertionInfo() { -m_lastAssertionInfo.macroName = StringRef(); -m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; -} + // Reset working state + resetAssertionInfo(); + m_lastResult = result; + } + void RunContext::resetAssertionInfo() { + m_lastAssertionInfo.macroName = StringRef(); + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + } -bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { -ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); -if (!sectionTracker.isOpen()) -return false; -m_activeSections.push_back(§ionTracker); + bool RunContext::sectionStarted(SectionInfo const& sectionInfo, Counts& assertions) { + ITracker& sectionTracker = SectionTracker::acquire( + m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + if (!sectionTracker.isOpen()) + return false; + m_activeSections.push_back(§ionTracker); -m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; -m_reporter->sectionStarting(sectionInfo); + m_reporter->sectionStarting(sectionInfo); -assertions = m_totals.assertions; + assertions = m_totals.assertions; -return true; -} -auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { -using namespace Generators; -GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); -assert( tracker.isOpen() ); -m_lastAssertionInfo.lineInfo = lineInfo; -return tracker; -} + return true; + } + auto RunContext::acquireGeneratorTracker(SourceLineInfo const& lineInfo) -> IGeneratorTracker& { + using namespace Generators; + GeneratorTracker& tracker = + GeneratorTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation("generator", lineInfo)); + assert(tracker.isOpen()); + m_lastAssertionInfo.lineInfo = lineInfo; + return tracker; + } -bool RunContext::testForMissingAssertions(Counts& assertions) { -if (assertions.total() != 0) -return false; -if (!m_config->warnAboutMissingAssertions()) -return false; -if (m_trackerContext.currentTracker().hasChildren()) -return false; -m_totals.assertions.failed++; -assertions.failed++; -return true; -} + bool RunContext::testForMissingAssertions(Counts& assertions) { + if (assertions.total() != 0) + return false; + if (!m_config->warnAboutMissingAssertions()) + return false; + if (m_trackerContext.currentTracker().hasChildren()) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } -void RunContext::sectionEnded(SectionEndInfo const & endInfo) { -Counts assertions = m_totals.assertions - endInfo.prevAssertions; -bool missingAssertions = testForMissingAssertions(assertions); + void RunContext::sectionEnded(SectionEndInfo const& endInfo) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); -if (!m_activeSections.empty()) { -m_activeSections.back()->close(); -m_activeSections.pop_back(); -} + if (!m_activeSections.empty()) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } -m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); -m_messages.clear(); -m_messageScopes.clear(); -} + m_reporter->sectionEnded( + SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_messages.clear(); + m_messageScopes.clear(); + } -void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { -if (m_unfinishedSections.empty()) -m_activeSections.back()->fail(); -else -m_activeSections.back()->close(); -m_activeSections.pop_back(); + void RunContext::sectionEndedEarly(SectionEndInfo const& endInfo) { + if (m_unfinishedSections.empty()) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); -m_unfinishedSections.push_back(endInfo); -} + m_unfinishedSections.push_back(endInfo); + } #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -void RunContext::benchmarkPreparing(std::string const& name) { -m_reporter->benchmarkPreparing(name); -} -void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { -m_reporter->benchmarkStarting( info ); -} -void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { -m_reporter->benchmarkEnded( stats ); -} -void RunContext::benchmarkFailed(std::string const & error) { -m_reporter->benchmarkFailed(error); -} + void RunContext::benchmarkPreparing(std::string const& name) { m_reporter->benchmarkPreparing(name); } + void RunContext::benchmarkStarting(BenchmarkInfo const& info) { m_reporter->benchmarkStarting(info); } + void RunContext::benchmarkEnded(BenchmarkStats<> const& stats) { m_reporter->benchmarkEnded(stats); } + void RunContext::benchmarkFailed(std::string const& error) { m_reporter->benchmarkFailed(error); } #endif // CATCH_CONFIG_ENABLE_BENCHMARKING -void RunContext::pushScopedMessage(MessageInfo const & message) { -m_messages.push_back(message); -} + void RunContext::pushScopedMessage(MessageInfo const& message) { m_messages.push_back(message); } -void RunContext::popScopedMessage(MessageInfo const & message) { -m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); -} + void RunContext::popScopedMessage(MessageInfo const& message) { + m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); + } -void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { -m_messageScopes.emplace_back( builder ); -} + void RunContext::emplaceUnscopedMessage(MessageBuilder const& builder) { m_messageScopes.emplace_back(builder); } -std::string RunContext::getCurrentTestName() const { -return m_activeTestCase -? m_activeTestCase->getTestCaseInfo().name -: std::string(); -} + std::string RunContext::getCurrentTestName() const { + return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name : std::string(); + } -const AssertionResult * RunContext::getLastResult() const { -return &(*m_lastResult); -} + const AssertionResult* RunContext::getLastResult() const { return &(*m_lastResult); } -void RunContext::exceptionEarlyReported() { -m_shouldReportUnexpected = false; -} + void RunContext::exceptionEarlyReported() { m_shouldReportUnexpected = false; } -void RunContext::handleFatalErrorCondition( StringRef message ) { -// First notify reporter that bad things happened -m_reporter->fatalErrorEncountered(message); + void RunContext::handleFatalErrorCondition(StringRef message) { + // First notify reporter that bad things happened + m_reporter->fatalErrorEncountered(message); -// Don't rebuild the result -- the stringification itself can cause more fatal errors -// Instead, fake a result data. -AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); -tempResult.message = static_cast(message); -AssertionResult result(m_lastAssertionInfo, tempResult); + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult(ResultWas::FatalErrorCondition, {false}); + tempResult.message = static_cast(message); + AssertionResult result(m_lastAssertionInfo, tempResult); -assertionEnded(result); + assertionEnded(result); -handleUnfinishedSections(); + handleUnfinishedSections(); -// Recreate section for test case (as we will lose the one that was in scope) -auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); -SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + // Recreate section for test case (as we will lose the one that was in scope) + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); -Counts assertions; -assertions.failed = 1; -SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); -m_reporter->sectionEnded(testCaseSectionStats); + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + m_reporter->sectionEnded(testCaseSectionStats); -auto const& testInfo = m_activeTestCase->getTestCaseInfo(); + auto const& testInfo = m_activeTestCase->getTestCaseInfo(); -Totals deltaTotals; -deltaTotals.testCases.failed = 1; -deltaTotals.assertions.failed = 1; -m_reporter->testCaseEnded(TestCaseStats(testInfo, -deltaTotals, -std::string(), -std::string(), -false)); -m_totals.testCases.failed++; -testGroupEnded(std::string(), m_totals, 1, 1); -m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); -} + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; + m_reporter->testCaseEnded(TestCaseStats(testInfo, deltaTotals, std::string(), std::string(), false)); + m_totals.testCases.failed++; + testGroupEnded(std::string(), m_totals, 1, 1); + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); + } -bool RunContext::lastAssertionPassed() { -return m_lastAssertionPassed; -} + bool RunContext::lastAssertionPassed() { return m_lastAssertionPassed; } -void RunContext::assertionPassed() { -m_lastAssertionPassed = true; -++m_totals.assertions.passed; -resetAssertionInfo(); -m_messageScopes.clear(); -} + void RunContext::assertionPassed() { + m_lastAssertionPassed = true; + ++m_totals.assertions.passed; + resetAssertionInfo(); + m_messageScopes.clear(); + } -bool RunContext::aborting() const { -return m_totals.assertions.failed >= static_cast(m_config->abortAfter()); -} + bool RunContext::aborting() const { + return m_totals.assertions.failed >= static_cast(m_config->abortAfter()); + } -void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { -auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); -SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); -m_reporter->sectionStarting(testCaseSection); -Counts prevAssertions = m_totals.assertions; -double duration = 0; -m_shouldReportUnexpected = true; -m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; + void RunContext::runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr) { + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + m_reporter->sectionStarting(testCaseSection); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + m_shouldReportUnexpected = true; + m_lastAssertionInfo = {"TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal}; -seedRng(*m_config); + seedRng(*m_config); -Timer timer; -CATCH_TRY { -if (m_reporter->getPreferences().shouldRedirectStdOut) { + Timer timer; + CATCH_TRY { + if (m_reporter->getPreferences().shouldRedirectStdOut) { #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); + RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); -timer.start(); -invokeActiveTestCase(); + timer.start(); + invokeActiveTestCase(); #else -OutputRedirect r(redirectedCout, redirectedCerr); -timer.start(); -invokeActiveTestCase(); + OutputRedirect r(redirectedCout, redirectedCerr); + timer.start(); + invokeActiveTestCase(); #endif -} else { -timer.start(); -invokeActiveTestCase(); -} -duration = timer.getElapsedSeconds(); -} CATCH_CATCH_ANON (TestFailureException&) { -// This just means the test was aborted due to failure -} CATCH_CATCH_ALL { -// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions -// are reported without translation at the point of origin. -if( m_shouldReportUnexpected ) { -AssertionReaction dummyReaction; -handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); -} -} -Counts assertions = m_totals.assertions - prevAssertions; -bool missingAssertions = testForMissingAssertions(assertions); + } else { + timer.start(); + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + CATCH_CATCH_ANON(TestFailureException&) { + // This just means the test was aborted due to failure + } + CATCH_CATCH_ALL { + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if (m_shouldReportUnexpected) { + AssertionReaction dummyReaction; + handleUnexpectedInflightException(m_lastAssertionInfo, translateActiveException(), dummyReaction); + } + } + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); -m_testCaseTracker->close(); -handleUnfinishedSections(); -m_messages.clear(); -m_messageScopes.clear(); + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + m_messageScopes.clear(); -SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); -m_reporter->sectionEnded(testCaseSectionStats); -} + SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + m_reporter->sectionEnded(testCaseSectionStats); + } -void RunContext::invokeActiveTestCase() { -FatalConditionHandler fatalConditionHandler; // Handle signals -m_activeTestCase->invoke(); -fatalConditionHandler.reset(); -} + void RunContext::invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } -void RunContext::handleUnfinishedSections() { -// If sections ended prematurely due to an exception we stored their -// infos here so we can tear them down outside the unwind process. -for (auto it = m_unfinishedSections.rbegin(), -itEnd = m_unfinishedSections.rend(); -it != itEnd; -++it) -sectionEnded(*it); -m_unfinishedSections.clear(); -} + void RunContext::handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for (auto it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it) + sectionEnded(*it); + m_unfinishedSections.clear(); + } -void RunContext::handleExpr( -AssertionInfo const& info, -ITransientExpression const& expr, -AssertionReaction& reaction -) { -m_reporter->assertionStarting( info ); + void RunContext::handleExpr(AssertionInfo const& info, ITransientExpression const& expr, + AssertionReaction& reaction) { + m_reporter->assertionStarting(info); -bool negated = isFalseTest( info.resultDisposition ); -bool result = expr.getResult() != negated; + bool negated = isFalseTest(info.resultDisposition); + bool result = expr.getResult() != negated; -if( result ) { -if (!m_includeSuccessfulResults) { -assertionPassed(); -} -else { -reportExpr(info, ResultWas::Ok, &expr, negated); -} -} -else { -reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); -populateReaction( reaction ); -} -} -void RunContext::reportExpr( -AssertionInfo const &info, -ResultWas::OfType resultType, -ITransientExpression const *expr, -bool negated ) { + if (result) { + if (!m_includeSuccessfulResults) { + assertionPassed(); + } else { + reportExpr(info, ResultWas::Ok, &expr, negated); + } + } else { + reportExpr(info, ResultWas::ExpressionFailed, &expr, negated); + populateReaction(reaction); + } + } + void RunContext::reportExpr(AssertionInfo const& info, ResultWas::OfType resultType, + ITransientExpression const* expr, bool negated) { -m_lastAssertionInfo = info; -AssertionResultData data( resultType, LazyExpression( negated ) ); + m_lastAssertionInfo = info; + AssertionResultData data(resultType, LazyExpression(negated)); -AssertionResult assertionResult{ info, data }; -assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + AssertionResult assertionResult{info, data}; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; -assertionEnded( assertionResult ); -} + assertionEnded(assertionResult); + } -void RunContext::handleMessage( -AssertionInfo const& info, -ResultWas::OfType resultType, -StringRef const& message, -AssertionReaction& reaction -) { -m_reporter->assertionStarting( info ); + void RunContext::handleMessage(AssertionInfo const& info, ResultWas::OfType resultType, StringRef const& message, + AssertionReaction& reaction) { + m_reporter->assertionStarting(info); -m_lastAssertionInfo = info; + m_lastAssertionInfo = info; -AssertionResultData data( resultType, LazyExpression( false ) ); -data.message = static_cast(message); -AssertionResult assertionResult{ m_lastAssertionInfo, data }; -assertionEnded( assertionResult ); -if( !assertionResult.isOk() ) -populateReaction( reaction ); -} -void RunContext::handleUnexpectedExceptionNotThrown( -AssertionInfo const& info, -AssertionReaction& reaction -) { -handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); -} + AssertionResultData data(resultType, LazyExpression(false)); + data.message = static_cast(message); + AssertionResult assertionResult{m_lastAssertionInfo, data}; + assertionEnded(assertionResult); + if (!assertionResult.isOk()) + populateReaction(reaction); + } + void RunContext::handleUnexpectedExceptionNotThrown(AssertionInfo const& info, AssertionReaction& reaction) { + handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); + } -void RunContext::handleUnexpectedInflightException( -AssertionInfo const& info, -std::string const& message, -AssertionReaction& reaction -) { -m_lastAssertionInfo = info; + void RunContext::handleUnexpectedInflightException(AssertionInfo const& info, std::string const& message, + AssertionReaction& reaction) { + m_lastAssertionInfo = info; -AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); -data.message = message; -AssertionResult assertionResult{ info, data }; -assertionEnded( assertionResult ); -populateReaction( reaction ); -} + AssertionResultData data(ResultWas::ThrewException, LazyExpression(false)); + data.message = message; + AssertionResult assertionResult{info, data}; + assertionEnded(assertionResult); + populateReaction(reaction); + } -void RunContext::populateReaction( AssertionReaction& reaction ) { -reaction.shouldDebugBreak = m_config->shouldDebugBreak(); -reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); -} + void RunContext::populateReaction(AssertionReaction& reaction) { + reaction.shouldDebugBreak = m_config->shouldDebugBreak(); + reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); + } -void RunContext::handleIncomplete( -AssertionInfo const& info -) { -m_lastAssertionInfo = info; + void RunContext::handleIncomplete(AssertionInfo const& info) { + m_lastAssertionInfo = info; -AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); -data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; -AssertionResult assertionResult{ info, data }; -assertionEnded( assertionResult ); -} -void RunContext::handleNonExpr( -AssertionInfo const &info, -ResultWas::OfType resultType, -AssertionReaction &reaction -) { -m_lastAssertionInfo = info; + AssertionResultData data(ResultWas::ThrewException, LazyExpression(false)); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + AssertionResult assertionResult{info, data}; + assertionEnded(assertionResult); + } + void RunContext::handleNonExpr(AssertionInfo const& info, ResultWas::OfType resultType, + AssertionReaction& reaction) { + m_lastAssertionInfo = info; -AssertionResultData data( resultType, LazyExpression( false ) ); -AssertionResult assertionResult{ info, data }; -assertionEnded( assertionResult ); + AssertionResultData data(resultType, LazyExpression(false)); + AssertionResult assertionResult{info, data}; + assertionEnded(assertionResult); -if( !assertionResult.isOk() ) -populateReaction( reaction ); -} + if (!assertionResult.isOk()) + populateReaction(reaction); + } -IResultCapture& getResultCapture() { -if (auto* capture = getCurrentContext().getResultCapture()) -return *capture; -else -CATCH_INTERNAL_ERROR("No result capture instance"); -} + IResultCapture& getResultCapture() { + if (auto* capture = getCurrentContext().getResultCapture()) + return *capture; + else + CATCH_INTERNAL_ERROR("No result capture instance"); + } -void seedRng(IConfig const& config) { -if (config.rngSeed() != 0) { -std::srand(config.rngSeed()); -rng().seed(config.rngSeed()); -} -} + void seedRng(IConfig const& config) { + if (config.rngSeed() != 0) { + std::srand(config.rngSeed()); + rng().seed(config.rngSeed()); + } + } -unsigned int rngSeed() { -return getCurrentContext().getConfig()->rngSeed(); -} + unsigned int rngSeed() { return getCurrentContext().getConfig()->rngSeed(); } } // end catch_run_context.cpp @@ -12933,27 +12427,23 @@ return getCurrentContext().getConfig()->rngSeed(); namespace Catch { -Section::Section( SectionInfo const& info ) -: m_info( info ), -m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) -{ -m_timer.start(); -} + Section::Section(SectionInfo const& info) + : m_info(info), m_sectionIncluded(getResultCapture().sectionStarted(m_info, m_assertions)) { + m_timer.start(); + } -Section::~Section() { -if( m_sectionIncluded ) { -SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; -if( uncaught_exceptions() ) -getResultCapture().sectionEndedEarly( endInfo ); -else -getResultCapture().sectionEnded( endInfo ); -} -} + Section::~Section() { + if (m_sectionIncluded) { + SectionEndInfo endInfo{m_info, m_assertions, m_timer.getElapsedSeconds()}; + if (uncaught_exceptions()) + getResultCapture().sectionEndedEarly(endInfo); + else + getResultCapture().sectionEnded(endInfo); + } + } -// This indicates whether the section should be executed or not -Section::operator bool() const { -return m_sectionIncluded; -} + // This indicates whether the section should be executed or not + Section::operator bool() const { return m_sectionIncluded; } } // end namespace Catch // end catch_section.cpp @@ -12961,12 +12451,8 @@ return m_sectionIncluded; namespace Catch { -SectionInfo::SectionInfo -( SourceLineInfo const& _lineInfo, -std::string const& _name ) -: name( _name ), -lineInfo( _lineInfo ) -{} + SectionInfo::SectionInfo(SourceLineInfo const& _lineInfo, std::string const& _name) + : name(_name), lineInfo(_lineInfo) {} } // end namespace Catch // end catch_section_info.cpp @@ -12978,46 +12464,45 @@ lineInfo( _lineInfo ) namespace Catch { -class Session : NonCopyable { -public: + class Session : NonCopyable { + public: + Session(); + ~Session() override; -Session(); -~Session() override; + void showHelp() const; + void libIdentify(); -void showHelp() const; -void libIdentify(); - -int applyCommandLine( int argc, char const * const * argv ); + int applyCommandLine(int argc, char const* const* argv); #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) -int applyCommandLine( int argc, wchar_t const * const * argv ); + int applyCommandLine(int argc, wchar_t const* const* argv); #endif -void useConfigData( ConfigData const& configData ); + void useConfigData(ConfigData const& configData); -template -int run(int argc, CharT const * const argv[]) { -if (m_startupExceptions) -return 1; -int returnCode = applyCommandLine(argc, argv); -if (returnCode == 0) -returnCode = run(); -return returnCode; -} + template int run(int argc, CharT const* const argv[]) { + if (m_startupExceptions) + return 1; + int returnCode = applyCommandLine(argc, argv); + if (returnCode == 0) + returnCode = run(); + return returnCode; + } -int run(); + int run(); -clara::Parser const& cli() const; -void cli( clara::Parser const& newParser ); -ConfigData& configData(); -Config& config(); -private: -int runInternal(); + clara::Parser const& cli() const; + void cli(clara::Parser const& newParser); + ConfigData& configData(); + Config& config(); -clara::Parser m_cli; -ConfigData m_configData; -std::shared_ptr m_config; -bool m_startupExceptions = false; -}; + private: + int runInternal(); + + clara::Parser m_cli; + ConfigData m_configData; + std::shared_ptr m_config; + bool m_startupExceptions = false; + }; } // end namespace Catch @@ -13028,317 +12513,303 @@ bool m_startupExceptions = false; namespace Catch { -// Versioning information -struct Version { -Version( Version const& ) = delete; -Version& operator=( Version const& ) = delete; -Version( unsigned int _majorVersion, -unsigned int _minorVersion, -unsigned int _patchNumber, -char const * const _branchName, -unsigned int _buildNumber ); + // Versioning information + struct Version { + Version(Version const&) = delete; + Version& operator=(Version const&) = delete; + Version(unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, + char const* const _branchName, unsigned int _buildNumber); -unsigned int const majorVersion; -unsigned int const minorVersion; -unsigned int const patchNumber; + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; -// buildNumber is only used if branchName is not null -char const * const branchName; -unsigned int const buildNumber; + // buildNumber is only used if branchName is not null + char const* const branchName; + unsigned int const buildNumber; -friend std::ostream& operator << ( std::ostream& os, Version const& version ); -}; + friend std::ostream& operator<<(std::ostream& os, Version const& version); + }; -Version const& libraryVersion(); + Version const& libraryVersion(); } // end catch_version.h #include #include -#include #include +#include namespace Catch { -namespace { -const int MaxExitCode = 255; + namespace { + const int MaxExitCode = 255; -IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { -auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); -CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); + IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { + auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); + CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); -return reporter; -} + return reporter; + } -IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { -if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { -return createReporter(config->getReporterName(), config); -} + IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { + if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { + return createReporter(config->getReporterName(), config); + } -// On older platforms, returning std::unique_ptr -// when the return type is std::unique_ptr -// doesn't compile without a std::move call. However, this causes -// a warning on newer platforms. Thus, we have to work around -// it a bit and downcast the pointer manually. -auto ret = std::unique_ptr(new ListeningReporter); -auto& multi = static_cast(*ret); -auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); -for (auto const& listener : listeners) { -multi.addListener(listener->create(Catch::ReporterConfig(config))); -} -multi.addReporter(createReporter(config->getReporterName(), config)); -return ret; -} + // On older platforms, returning std::unique_ptr + // when the return type is std::unique_ptr + // doesn't compile without a std::move call. However, this causes + // a warning on newer platforms. Thus, we have to work around + // it a bit and downcast the pointer manually. + auto ret = std::unique_ptr(new ListeningReporter); + auto& multi = static_cast(*ret); + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) { + multi.addListener(listener->create(Catch::ReporterConfig(config))); + } + multi.addReporter(createReporter(config->getReporterName(), config)); + return ret; + } -class TestGroup { -public: -explicit TestGroup(std::shared_ptr const& config) -: m_config{config} -, m_context{config, makeReporter(config)} -{ -auto const& allTestCases = getAllTestCasesSorted(*m_config); -m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config); -auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); + class TestGroup { + public: + explicit TestGroup(std::shared_ptr const& config) + : m_config{config}, m_context{config, makeReporter(config)} { + auto const& allTestCases = getAllTestCasesSorted(*m_config); + m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config); + auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); -if (m_matches.empty() && invalidArgs.empty()) { -for (auto const& test : allTestCases) -if (!test.isHidden()) -m_tests.emplace(&test); -} else { -for (auto const& match : m_matches) -m_tests.insert(match.tests.begin(), match.tests.end()); -} -} + if (m_matches.empty() && invalidArgs.empty()) { + for (auto const& test : allTestCases) + if (!test.isHidden()) + m_tests.emplace(&test); + } else { + for (auto const& match : m_matches) + m_tests.insert(match.tests.begin(), match.tests.end()); + } + } -Totals execute() { -auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); -Totals totals; -m_context.testGroupStarting(m_config->name(), 1, 1); -for (auto const& testCase : m_tests) { -if (!m_context.aborting()) -totals += m_context.runTest(*testCase); -else -m_context.reporter().skipTest(*testCase); -} + Totals execute() { + auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); + Totals totals; + m_context.testGroupStarting(m_config->name(), 1, 1); + for (auto const& testCase : m_tests) { + if (!m_context.aborting()) + totals += m_context.runTest(*testCase); + else + m_context.reporter().skipTest(*testCase); + } -for (auto const& match : m_matches) { -if (match.tests.empty()) { -m_context.reporter().noMatchingTestCases(match.name); -totals.error = -1; -} -} + for (auto const& match : m_matches) { + if (match.tests.empty()) { + m_context.reporter().noMatchingTestCases(match.name); + totals.error = -1; + } + } -if (!invalidArgs.empty()) { -for (auto const& invalidArg: invalidArgs) -m_context.reporter().reportInvalidArguments(invalidArg); -} + if (!invalidArgs.empty()) { + for (auto const& invalidArg : invalidArgs) + m_context.reporter().reportInvalidArguments(invalidArg); + } -m_context.testGroupEnded(m_config->name(), totals, 1, 1); -return totals; -} + m_context.testGroupEnded(m_config->name(), totals, 1, 1); + return totals; + } -private: -using Tests = std::set; + private: + using Tests = std::set; -std::shared_ptr m_config; -RunContext m_context; -Tests m_tests; -TestSpec::Matches m_matches; -}; + std::shared_ptr m_config; + RunContext m_context; + Tests m_tests; + TestSpec::Matches m_matches; + }; -void applyFilenamesAsTags(Catch::IConfig const& config) { -auto& tests = const_cast&>(getAllTestCasesSorted(config)); -for (auto& testCase : tests) { -auto tags = testCase.tags; + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; -std::string filename = testCase.lineInfo.file; -auto lastSlash = filename.find_last_of("\\/"); -if (lastSlash != std::string::npos) { -filename.erase(0, lastSlash); -filename[0] = '#'; -} + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[0] = '#'; + } -auto lastDot = filename.find_last_of('.'); -if (lastDot != std::string::npos) { -filename.erase(lastDot); -} + auto lastDot = filename.find_last_of('.'); + if (lastDot != std::string::npos) { + filename.erase(lastDot); + } -tags.push_back(std::move(filename)); -setTags(testCase, tags); -} -} + tags.push_back(std::move(filename)); + setTags(testCase, tags); + } + } -} // anon namespace + } // anon namespace -Session::Session() { -static bool alreadyInstantiated = false; -if( alreadyInstantiated ) { -CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } -CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } -} + Session::Session() { + static bool alreadyInstantiated = false; + if (alreadyInstantiated) { + CATCH_TRY { CATCH_INTERNAL_ERROR("Only one instance of Catch::Session can ever be used"); } + CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } + } // There cannot be exceptions at startup in no-exception mode. #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); -if ( !exceptions.empty() ) { -config(); -getCurrentMutableContext().setConfig(m_config); + const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); + if (!exceptions.empty()) { + config(); + getCurrentMutableContext().setConfig(m_config); -m_startupExceptions = true; -Colour colourGuard( Colour::Red ); -Catch::cerr() << "Errors occurred during startup!" << '\n'; -// iterate over all exceptions and notify user -for ( const auto& ex_ptr : exceptions ) { -try { -std::rethrow_exception(ex_ptr); -} catch ( std::exception const& ex ) { -Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; -} -} -} + m_startupExceptions = true; + Colour colourGuard(Colour::Red); + Catch::cerr() << "Errors occurred during startup!" << '\n'; + // iterate over all exceptions and notify user + for (const auto& ex_ptr : exceptions) { + try { + std::rethrow_exception(ex_ptr); + } catch (std::exception const& ex) { + Catch::cerr() << Column(ex.what()).indent(2) << '\n'; + } + } + } #endif -alreadyInstantiated = true; -m_cli = makeCommandLineParser( m_configData ); -} -Session::~Session() { -Catch::cleanUp(); -} + alreadyInstantiated = true; + m_cli = makeCommandLineParser(m_configData); + } + Session::~Session() { Catch::cleanUp(); } -void Session::showHelp() const { -Catch::cout() -<< "\nCatch v" << libraryVersion() << "\n" -<< m_cli << std::endl -<< "For more detailed usage please see the project docs\n" << std::endl; -} -void Session::libIdentify() { -Catch::cout() -<< std::left << std::setw(16) << "description: " << "A Catch2 test executable\n" -<< std::left << std::setw(16) << "category: " << "testframework\n" -<< std::left << std::setw(16) << "framework: " << "Catch Test\n" -<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; -} + void Session::showHelp() const { + Catch::cout() << "\nCatch v" << libraryVersion() << "\n" + << m_cli << std::endl + << "For more detailed usage please see the project docs\n" + << std::endl; + } + void Session::libIdentify() { + Catch::cout() << std::left << std::setw(16) << "description: " + << "A Catch2 test executable\n" + << std::left << std::setw(16) << "category: " + << "testframework\n" + << std::left << std::setw(16) << "framework: " + << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } -int Session::applyCommandLine( int argc, char const * const * argv ) { -if( m_startupExceptions ) -return 1; + int Session::applyCommandLine(int argc, char const* const* argv) { + if (m_startupExceptions) + return 1; -auto result = m_cli.parse( clara::Args( argc, argv ) ); -if( !result ) { -config(); -getCurrentMutableContext().setConfig(m_config); -Catch::cerr() -<< Colour( Colour::Red ) -<< "\nError(s) in input:\n" -<< Column( result.errorMessage() ).indent( 2 ) -<< "\n\n"; -Catch::cerr() << "Run with -? for usage\n" << std::endl; -return MaxExitCode; -} + auto result = m_cli.parse(clara::Args(argc, argv)); + if (!result) { + config(); + getCurrentMutableContext().setConfig(m_config); + Catch::cerr() << Colour(Colour::Red) << "\nError(s) in input:\n" + << Column(result.errorMessage()).indent(2) << "\n\n"; + Catch::cerr() << "Try with -? for usage\n" << std::endl; + return MaxExitCode; + } -if( m_configData.showHelp ) -showHelp(); -if( m_configData.libIdentify ) -libIdentify(); -m_config.reset(); -return 0; -} + if (m_configData.showHelp) + showHelp(); + if (m_configData.libIdentify) + libIdentify(); + m_config.reset(); + return 0; + } #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) -int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { + int Session::applyCommandLine(int argc, wchar_t const* const* argv) { -char **utf8Argv = new char *[ argc ]; + char** utf8Argv = new char*[argc]; -for ( int i = 0; i < argc; ++i ) { -int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + for (int i = 0; i < argc; ++i) { + int bufSize = WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL); -utf8Argv[ i ] = new char[ bufSize ]; + utf8Argv[i] = new char[bufSize]; -WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); -} + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL); + } -int returnCode = applyCommandLine( argc, utf8Argv ); + int returnCode = applyCommandLine(argc, utf8Argv); -for ( int i = 0; i < argc; ++i ) -delete [] utf8Argv[ i ]; + for (int i = 0; i < argc; ++i) + delete[] utf8Argv[i]; -delete [] utf8Argv; + delete[] utf8Argv; -return returnCode; -} + return returnCode; + } #endif -void Session::useConfigData( ConfigData const& configData ) { -m_configData = configData; -m_config.reset(); -} + void Session::useConfigData(ConfigData const& configData) { + m_configData = configData; + m_config.reset(); + } -int Session::run() { -if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { -Catch::cout() << "...waiting for enter/ return before starting" << std::endl; -static_cast(std::getchar()); -} -int exitCode = runInternal(); -if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { -Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; -static_cast(std::getchar()); -} -return exitCode; -} + int Session::run() { + if ((m_configData.waitForKeypress & WaitForKeypress::BeforeStart) != 0) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast(std::getchar()); + } + int exitCode = runInternal(); + if ((m_configData.waitForKeypress & WaitForKeypress::BeforeExit) != 0) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast(std::getchar()); + } + return exitCode; + } -clara::Parser const& Session::cli() const { -return m_cli; -} -void Session::cli( clara::Parser const& newParser ) { -m_cli = newParser; -} -ConfigData& Session::configData() { -return m_configData; -} -Config& Session::config() { -if( !m_config ) -m_config = std::make_shared( m_configData ); -return *m_config; -} + clara::Parser const& Session::cli() const { return m_cli; } + void Session::cli(clara::Parser const& newParser) { m_cli = newParser; } + ConfigData& Session::configData() { return m_configData; } + Config& Session::config() { + if (!m_config) + m_config = std::make_shared(m_configData); + return *m_config; + } -int Session::runInternal() { -if( m_startupExceptions ) -return 1; + int Session::runInternal() { + if (m_startupExceptions) + return 1; -if (m_configData.showHelp || m_configData.libIdentify) { -return 0; -} + if (m_configData.showHelp || m_configData.libIdentify) { + return 0; + } -CATCH_TRY { -config(); // Force config to be constructed + CATCH_TRY { + config(); // Force config to be constructed -seedRng( *m_config ); + seedRng(*m_config); -if( m_configData.filenamesAsTags ) -applyFilenamesAsTags( *m_config ); + if (m_configData.filenamesAsTags) + applyFilenamesAsTags(*m_config); -// Handle list request -if( Option listed = list( m_config ) ) -return static_cast( *listed ); + // Handle list request + if (Option listed = list(m_config)) + return static_cast(*listed); -TestGroup tests { m_config }; -auto const totals = tests.execute(); + TestGroup tests{m_config}; + auto const totals = tests.execute(); -if( m_config->warnAboutNoTests() && totals.error == -1 ) -return 2; + if (m_config->warnAboutNoTests() && totals.error == -1) + return 2; -// Note that on unices only the lower 8 bits are usually used, clamping -// the return value to 255 prevents false negative when some multiple -// of 256 tests has failed -return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); -} + // Note that on unices only the lower 8 bits are usually used, clamping + // the return value to 255 prevents false negative when some multiple + // of 256 tests has failed + return (std::min)(MaxExitCode, (std::max)(totals.error, static_cast(totals.assertions.failed))); + } #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -catch( std::exception& ex ) { -Catch::cerr() << ex.what() << std::endl; -return MaxExitCode; -} + catch (std::exception& ex) { + Catch::cerr() << ex.what() << std::endl; + return MaxExitCode; + } #endif -} + } } // end namespace Catch // end catch_session.cpp @@ -13348,382 +12819,352 @@ return MaxExitCode; namespace Catch { -namespace { -static auto getSingletons() -> std::vector*& { -static std::vector* g_singletons = nullptr; -if( !g_singletons ) -g_singletons = new std::vector(); -return g_singletons; -} -} + namespace { + static auto getSingletons() -> std::vector*& { + static std::vector* g_singletons = nullptr; + if (!g_singletons) + g_singletons = new std::vector(); + return g_singletons; + } + } -ISingleton::~ISingleton() {} + ISingleton::~ISingleton() {} -void addSingleton(ISingleton* singleton ) { -getSingletons()->push_back( singleton ); -} -void cleanupSingletons() { -auto& singletons = getSingletons(); -for( auto singleton : *singletons ) -delete singleton; -delete singletons; -singletons = nullptr; -} + void addSingleton(ISingleton* singleton) { getSingletons()->push_back(singleton); } + void cleanupSingletons() { + auto& singletons = getSingletons(); + for (auto singleton : *singletons) + delete singleton; + delete singletons; + singletons = nullptr; + } } // namespace Catch // end catch_singletons.cpp // start catch_startup_exception_registry.cpp namespace Catch { -void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { -CATCH_TRY { -m_exceptions.push_back(exception); -} CATCH_CATCH_ALL { -// If we run out of memory during start-up there's really not a lot more we can do about it -std::terminate(); -} -} + void StartupExceptionRegistry::add(std::exception_ptr const& exception) noexcept { + CATCH_TRY { m_exceptions.push_back(exception); } + CATCH_CATCH_ALL { + // If we run out of memory during start-up there's really not a lot more we can do about it + std::terminate(); + } + } -std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { -return m_exceptions; -} + std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { + return m_exceptions; + } } // end namespace Catch // end catch_startup_exception_registry.cpp // start catch_stream.cpp #include -#include #include +#include +#include #include #include -#include namespace Catch { -Catch::IStream::~IStream() = default; + Catch::IStream::~IStream() = default; -namespace Detail { namespace { -template -class StreamBufImpl : public std::streambuf { -char data[bufferSize]; -WriterF m_writer; + namespace Detail { + namespace { + template class StreamBufImpl : public std::streambuf { + char data[bufferSize]; + WriterF m_writer; -public: -StreamBufImpl() { -setp( data, data + sizeof(data) ); -} + public: + StreamBufImpl() { setp(data, data + sizeof(data)); } -~StreamBufImpl() noexcept { -StreamBufImpl::sync(); -} + ~StreamBufImpl() noexcept { StreamBufImpl::sync(); } -private: -int overflow( int c ) override { -sync(); + private: + int overflow(int c) override { + sync(); -if( c != EOF ) { -if( pbase() == epptr() ) -m_writer( std::string( 1, static_cast( c ) ) ); -else -sputc( static_cast( c ) ); -} -return 0; -} + if (c != EOF) { + if (pbase() == epptr()) + m_writer(std::string(1, static_cast(c))); + else + sputc(static_cast(c)); + } + return 0; + } -int sync() override { -if( pbase() != pptr() ) { -m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); -setp( pbase(), epptr() ); -} -return 0; -} -}; + int sync() override { + if (pbase() != pptr()) { + m_writer(std::string(pbase(), static_cast(pptr() - pbase()))); + setp(pbase(), epptr()); + } + return 0; + } + }; -/////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// -struct OutputDebugWriter { + struct OutputDebugWriter { -void operator()( std::string const&str ) { -writeToDebugConsole( str ); -} -}; + void operator()(std::string const& str) { writeToDebugConsole(str); } + }; -/////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// -class FileStream : public IStream { -mutable std::ofstream m_ofs; -public: -FileStream( StringRef filename ) { -m_ofs.open( filename.c_str() ); -CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); -} -~FileStream() override = default; -public: // IStream -std::ostream& stream() const override { -return m_ofs; -} -}; + class FileStream : public IStream { + mutable std::ofstream m_ofs; -/////////////////////////////////////////////////////////////////////////// + public: + FileStream(StringRef filename) { + m_ofs.open(filename.c_str()); + CATCH_ENFORCE(!m_ofs.fail(), "Unable to open file: '" << filename << "'"); + } + ~FileStream() override = default; -class CoutStream : public IStream { -mutable std::ostream m_os; -public: -// Store the streambuf from cout up-front because -// cout may get redirected when running tests -CoutStream() : m_os( Catch::cout().rdbuf() ) {} -~CoutStream() override = default; + public: // IStream + std::ostream& stream() const override { return m_ofs; } + }; -public: // IStream -std::ostream& stream() const override { return m_os; } -}; + /////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////// + class CoutStream : public IStream { + mutable std::ostream m_os; -class DebugOutStream : public IStream { -std::unique_ptr> m_streamBuf; -mutable std::ostream m_os; -public: -DebugOutStream() -: m_streamBuf( new StreamBufImpl() ), -m_os( m_streamBuf.get() ) -{} + public: + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream() : m_os(Catch::cout().rdbuf()) {} + ~CoutStream() override = default; -~DebugOutStream() override = default; + public: // IStream + std::ostream& stream() const override { return m_os; } + }; -public: // IStream -std::ostream& stream() const override { return m_os; } -}; + /////////////////////////////////////////////////////////////////////////// -}} // namespace anon::detail + class DebugOutStream : public IStream { + std::unique_ptr> m_streamBuf; + mutable std::ostream m_os; -/////////////////////////////////////////////////////////////////////////// + public: + DebugOutStream() : m_streamBuf(new StreamBufImpl()), m_os(m_streamBuf.get()) {} -auto makeStream( StringRef const &filename ) -> IStream const* { -if( filename.empty() ) -return new Detail::CoutStream(); -else if( filename[0] == '%' ) { -if( filename == "%debug" ) -return new Detail::DebugOutStream(); -else -CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); -} -else -return new Detail::FileStream( filename ); -} + ~DebugOutStream() override = default; -// This class encapsulates the idea of a pool of ostringstreams that can be reused. -struct StringStreams { -std::vector> m_streams; -std::vector m_unused; -std::ostringstream m_referenceStream; // Used for copy state/ flags from + public: // IStream + std::ostream& stream() const override { return m_os; } + }; -auto add() -> std::size_t { -if( m_unused.empty() ) { -m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); -return m_streams.size()-1; -} -else { -auto index = m_unused.back(); -m_unused.pop_back(); -return index; -} -} + } + } // namespace anon::detail -void release( std::size_t index ) { -m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state -m_unused.push_back(index); -} -}; + /////////////////////////////////////////////////////////////////////////// -ReusableStringStream::ReusableStringStream() -: m_index( Singleton::getMutable().add() ), -m_oss( Singleton::getMutable().m_streams[m_index].get() ) -{} + auto makeStream(StringRef const& filename) -> IStream const* { + if (filename.empty()) + return new Detail::CoutStream(); + else if (filename[0] == '%') { + if (filename == "%debug") + return new Detail::DebugOutStream(); + else + CATCH_ERROR("Unrecognised stream: '" << filename << "'"); + } else + return new Detail::FileStream(filename); + } -ReusableStringStream::~ReusableStringStream() { -static_cast( m_oss )->str(""); -m_oss->clear(); -Singleton::getMutable().release( m_index ); -} + // This class encapsulates the idea of a pool of ostringstreams that can be reused. + struct StringStreams { + std::vector> m_streams; + std::vector m_unused; + std::ostringstream m_referenceStream; // Used for copy state/ flags from -auto ReusableStringStream::str() const -> std::string { -return static_cast( m_oss )->str(); -} + auto add() -> std::size_t { + if (m_unused.empty()) { + m_streams.push_back(std::unique_ptr(new std::ostringstream)); + return m_streams.size() - 1; + } else { + auto index = m_unused.back(); + m_unused.pop_back(); + return index; + } + } -/////////////////////////////////////////////////////////////////////////// + void release(std::size_t index) { + m_streams[index]->copyfmt(m_referenceStream); // Restore initial flags and other state + m_unused.push_back(index); + } + }; + + ReusableStringStream::ReusableStringStream() + : m_index(Singleton::getMutable().add()), + m_oss(Singleton::getMutable().m_streams[m_index].get()) {} + + ReusableStringStream::~ReusableStringStream() { + static_cast(m_oss)->str(""); + m_oss->clear(); + Singleton::getMutable().release(m_index); + } + + auto ReusableStringStream::str() const -> std::string { return static_cast(m_oss)->str(); } + + /////////////////////////////////////////////////////////////////////////// #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions -std::ostream& cout() { return std::cout; } -std::ostream& cerr() { return std::cerr; } -std::ostream& clog() { return std::clog; } + std::ostream& cout() { return std::cout; } + std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { return std::clog; } #endif } // end catch_stream.cpp // start catch_string_manip.cpp #include -#include -#include #include +#include +#include #include namespace Catch { -namespace { -char toLowerCh(char c) { -return static_cast( std::tolower( c ) ); -} -} + namespace { + char toLowerCh(char c) { return static_cast(std::tolower(c)); } + } -bool startsWith( std::string const& s, std::string const& prefix ) { -return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); -} -bool startsWith( std::string const& s, char prefix ) { -return !s.empty() && s[0] == prefix; -} -bool endsWith( std::string const& s, std::string const& suffix ) { -return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); -} -bool endsWith( std::string const& s, char suffix ) { -return !s.empty() && s[s.size()-1] == suffix; -} -bool contains( std::string const& s, std::string const& infix ) { -return s.find( infix ) != std::string::npos; -} -void toLowerInPlace( std::string& s ) { -std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); -} -std::string toLower( std::string const& s ) { -std::string lc = s; -toLowerInPlace( lc ); -return lc; -} -std::string trim( std::string const& str ) { -static char const* whitespaceChars = "\n\r\t "; -std::string::size_type start = str.find_first_not_of( whitespaceChars ); -std::string::size_type end = str.find_last_not_of( whitespaceChars ); + bool startsWith(std::string const& s, std::string const& prefix) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith(std::string const& s, char prefix) { return !s.empty() && s[0] == prefix; } + bool endsWith(std::string const& s, std::string const& suffix) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith(std::string const& s, char suffix) { return !s.empty() && s[s.size() - 1] == suffix; } + bool contains(std::string const& s, std::string const& infix) { return s.find(infix) != std::string::npos; } + void toLowerInPlace(std::string& s) { std::transform(s.begin(), s.end(), s.begin(), toLowerCh); } + std::string toLower(std::string const& s) { + std::string lc = s; + toLowerInPlace(lc); + return lc; + } + std::string trim(std::string const& str) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of(whitespaceChars); + std::string::size_type end = str.find_last_not_of(whitespaceChars); -return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); -} + return start != std::string::npos ? str.substr(start, 1 + end - start) : std::string(); + } -StringRef trim(StringRef ref) { -const auto is_ws = [](char c) { -return c == ' ' || c == '\t' || c == '\n' || c == '\r'; -}; -size_t real_begin = 0; -while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; } -size_t real_end = ref.size(); -while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; } + StringRef trim(StringRef ref) { + const auto is_ws = [](char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; }; + size_t real_begin = 0; + while (real_begin < ref.size() && is_ws(ref[real_begin])) { + ++real_begin; + } + size_t real_end = ref.size(); + while (real_end > real_begin && is_ws(ref[real_end - 1])) { + --real_end; + } -return ref.substr(real_begin, real_end - real_begin); -} + return ref.substr(real_begin, real_end - real_begin); + } -bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { -bool replaced = false; -std::size_t i = str.find( replaceThis ); -while( i != std::string::npos ) { -replaced = true; -str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); -if( i < str.size()-withThis.size() ) -i = str.find( replaceThis, i+withThis.size() ); -else -i = std::string::npos; -} -return replaced; -} + bool replaceInPlace(std::string& str, std::string const& replaceThis, std::string const& withThis) { + bool replaced = false; + std::size_t i = str.find(replaceThis); + while (i != std::string::npos) { + replaced = true; + str = str.substr(0, i) + withThis + str.substr(i + replaceThis.size()); + if (i < str.size() - withThis.size()) + i = str.find(replaceThis, i + withThis.size()); + else + i = std::string::npos; + } + return replaced; + } -std::vector splitStringRef( StringRef str, char delimiter ) { -std::vector subStrings; -std::size_t start = 0; -for(std::size_t pos = 0; pos < str.size(); ++pos ) { -if( str[pos] == delimiter ) { -if( pos - start > 1 ) -subStrings.push_back( str.substr( start, pos-start ) ); -start = pos+1; -} -} -if( start < str.size() ) -subStrings.push_back( str.substr( start, str.size()-start ) ); -return subStrings; -} + std::vector splitStringRef(StringRef str, char delimiter) { + std::vector subStrings; + std::size_t start = 0; + for (std::size_t pos = 0; pos < str.size(); ++pos) { + if (str[pos] == delimiter) { + if (pos - start > 1) + subStrings.push_back(str.substr(start, pos - start)); + start = pos + 1; + } + } + if (start < str.size()) + subStrings.push_back(str.substr(start, str.size() - start)); + return subStrings; + } -pluralise::pluralise( std::size_t count, std::string const& label ) -: m_count( count ), -m_label( label ) -{} + pluralise::pluralise(std::size_t count, std::string const& label) : m_count(count), m_label(label) {} -std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { -os << pluraliser.m_count << ' ' << pluraliser.m_label; -if( pluraliser.m_count != 1 ) -os << 's'; -return os; -} + std::ostream& operator<<(std::ostream& os, pluralise const& pluraliser) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if (pluraliser.m_count != 1) + os << 's'; + return os; + } } // end catch_string_manip.cpp // start catch_stringref.cpp #include -#include -#include #include +#include +#include namespace Catch { -StringRef::StringRef( char const* rawChars ) noexcept -: StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) -{} + StringRef::StringRef(char const* rawChars) noexcept + : StringRef(rawChars, static_cast(std::strlen(rawChars))) {} -auto StringRef::c_str() const -> char const* { -CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance"); -return m_start; -} -auto StringRef::data() const noexcept -> char const* { -return m_start; -} + auto StringRef::c_str() const -> char const* { + CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance"); + return m_start; + } + auto StringRef::data() const noexcept -> char const* { return m_start; } -auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { -if (start < m_size) { -return StringRef(m_start + start, (std::min)(m_size - start, size)); -} else { -return StringRef(); -} -} -auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { -return m_size == other.m_size -&& (std::memcmp( m_start, other.m_start, m_size ) == 0); -} + auto StringRef::substr(size_type start, size_type size) const noexcept -> StringRef { + if (start < m_size) { + return StringRef(m_start + start, (std::min)(m_size - start, size)); + } else { + return StringRef(); + } + } + auto StringRef::operator==(StringRef const& other) const noexcept -> bool { + return m_size == other.m_size && (std::memcmp(m_start, other.m_start, m_size) == 0); + } -auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { -return os.write(str.data(), str.size()); -} + auto operator<<(std::ostream& os, StringRef const& str) -> std::ostream& { + return os.write(str.data(), str.size()); + } -auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { -lhs.append(rhs.data(), rhs.size()); -return lhs; -} + auto operator+=(std::string& lhs, StringRef const& rhs) -> std::string& { + lhs.append(rhs.data(), rhs.size()); + return lhs; + } } // namespace Catch // end catch_stringref.cpp // start catch_tag_alias.cpp namespace Catch { -TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} + TagAlias::TagAlias(std::string const& _tag, SourceLineInfo _lineInfo) : tag(_tag), lineInfo(_lineInfo) {} } // end catch_tag_alias.cpp // start catch_tag_alias_autoregistrar.cpp namespace Catch { -RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { -CATCH_TRY { -getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); -} CATCH_CATCH_ALL { -// Do not throw when constructing global objects, instead register the exception to be processed later -getMutableRegistryHub().registerStartupException(); -} -} + RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { + CATCH_TRY { getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); } + CATCH_CATCH_ALL { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } } // end catch_tag_alias_autoregistrar.cpp @@ -13733,216 +13174,185 @@ getMutableRegistryHub().registerStartupException(); namespace Catch { -TagAliasRegistry::~TagAliasRegistry() {} + TagAliasRegistry::~TagAliasRegistry() {} -TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { -auto it = m_registry.find( alias ); -if( it != m_registry.end() ) -return &(it->second); -else -return nullptr; -} + TagAlias const* TagAliasRegistry::find(std::string const& alias) const { + auto it = m_registry.find(alias); + if (it != m_registry.end()) + return &(it->second); + else + return nullptr; + } -std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { -std::string expandedTestSpec = unexpandedTestSpec; -for( auto const& registryKvp : m_registry ) { -std::size_t pos = expandedTestSpec.find( registryKvp.first ); -if( pos != std::string::npos ) { -expandedTestSpec = expandedTestSpec.substr( 0, pos ) + -registryKvp.second.tag + -expandedTestSpec.substr( pos + registryKvp.first.size() ); -} -} -return expandedTestSpec; -} + std::string TagAliasRegistry::expandAliases(std::string const& unexpandedTestSpec) const { + std::string expandedTestSpec = unexpandedTestSpec; + for (auto const& registryKvp : m_registry) { + std::size_t pos = expandedTestSpec.find(registryKvp.first); + if (pos != std::string::npos) { + expandedTestSpec = expandedTestSpec.substr(0, pos) + registryKvp.second.tag + + expandedTestSpec.substr(pos + registryKvp.first.size()); + } + } + return expandedTestSpec; + } -void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { -CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), -"error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); + void TagAliasRegistry::add(std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo) { + CATCH_ENFORCE(startsWith(alias, "[@") && endsWith(alias, ']'), + "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" + << lineInfo); -CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, -"error: tag alias, '" << alias << "' already registered.\n" -<< "\tFirst seen at: " << find(alias)->lineInfo << "\n" -<< "\tRedefined at: " << lineInfo ); -} + CATCH_ENFORCE(m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, + "error: tag alias, '" << alias << "' already registered.\n" + << "\tFirst seen at: " << find(alias)->lineInfo << "\n" + << "\tRedefined at: " << lineInfo); + } -ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry::~ITagAliasRegistry() {} -ITagAliasRegistry const& ITagAliasRegistry::get() { -return getRegistryHub().getTagAliasRegistry(); -} + ITagAliasRegistry const& ITagAliasRegistry::get() { return getRegistryHub().getTagAliasRegistry(); } } // end namespace Catch // end catch_tag_alias_registry.cpp // start catch_test_case_info.cpp +#include #include #include -#include #include namespace Catch { -namespace { -TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { -if( startsWith( tag, '.' ) || -tag == "!hide" ) -return TestCaseInfo::IsHidden; -else if( tag == "!throws" ) -return TestCaseInfo::Throws; -else if( tag == "!shouldfail" ) -return TestCaseInfo::ShouldFail; -else if( tag == "!mayfail" ) -return TestCaseInfo::MayFail; -else if( tag == "!nonportable" ) -return TestCaseInfo::NonPortable; -else if( tag == "!benchmark" ) -return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); -else -return TestCaseInfo::None; -} -bool isReservedTag( std::string const& tag ) { -return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); -} -void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { -CATCH_ENFORCE( !isReservedTag(tag), -"Tag name: [" << tag << "] is not allowed.\n" -<< "Tag names starting with non alphanumeric characters are reserved\n" -<< _lineInfo ); -} -} + namespace { + TestCaseInfo::SpecialProperties parseSpecialTag(std::string const& tag) { + if (startsWith(tag, '.') || tag == "!hide") + return TestCaseInfo::IsHidden; + else if (tag == "!throws") + return TestCaseInfo::Throws; + else if (tag == "!shouldfail") + return TestCaseInfo::ShouldFail; + else if (tag == "!mayfail") + return TestCaseInfo::MayFail; + else if (tag == "!nonportable") + return TestCaseInfo::NonPortable; + else if (tag == "!benchmark") + return static_cast(TestCaseInfo::Benchmark | TestCaseInfo::IsHidden); + else + return TestCaseInfo::None; + } + bool isReservedTag(std::string const& tag) { + return parseSpecialTag(tag) == TestCaseInfo::None && tag.size() > 0 && + !std::isalnum(static_cast(tag[0])); + } + void enforceNotReservedTag(std::string const& tag, SourceLineInfo const& _lineInfo) { + CATCH_ENFORCE(!isReservedTag(tag), + "Tag name: [" << tag << "] is not allowed.\n" + << "Tag names starting with non alphanumeric characters are reserved\n" + << _lineInfo); + } + } -TestCase makeTestCase( ITestInvoker* _testCase, -std::string const& _className, -NameAndTags const& nameAndTags, -SourceLineInfo const& _lineInfo ) -{ -bool isHidden = false; + TestCase makeTestCase(ITestInvoker* _testCase, std::string const& _className, NameAndTags const& nameAndTags, + SourceLineInfo const& _lineInfo) { + bool isHidden = false; -// Parse out tags -std::vector tags; -std::string desc, tag; -bool inTag = false; -for (char c : nameAndTags.tags) { -if( !inTag ) { -if( c == '[' ) -inTag = true; -else -desc += c; -} -else { -if( c == ']' ) { -TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); -if( ( prop & TestCaseInfo::IsHidden ) != 0 ) -isHidden = true; -else if( prop == TestCaseInfo::None ) -enforceNotReservedTag( tag, _lineInfo ); + // Parse out tags + std::vector tags; + std::string desc, tag; + bool inTag = false; + for (char c : nameAndTags.tags) { + if (!inTag) { + if (c == '[') + inTag = true; + else + desc += c; + } else { + if (c == ']') { + TestCaseInfo::SpecialProperties prop = parseSpecialTag(tag); + if ((prop & TestCaseInfo::IsHidden) != 0) + isHidden = true; + else if (prop == TestCaseInfo::None) + enforceNotReservedTag(tag, _lineInfo); -// Merged hide tags like `[.approvals]` should be added as -// `[.][approvals]`. The `[.]` is added at later point, so -// we only strip the prefix -if (startsWith(tag, '.') && tag.size() > 1) { -tag.erase(0, 1); -} -tags.push_back( tag ); -tag.clear(); -inTag = false; -} -else -tag += c; -} -} -if( isHidden ) { -tags.push_back( "." ); -} + // Merged hide tags like `[.approvals]` should be added as + // `[.][approvals]`. The `[.]` is added at later point, so + // we only strip the prefix + if (startsWith(tag, '.') && tag.size() > 1) { + tag.erase(0, 1); + } + tags.push_back(tag); + tag.clear(); + inTag = false; + } else + tag += c; + } + } + if (isHidden) { + tags.push_back("."); + } -TestCaseInfo info( static_cast(nameAndTags.name), _className, desc, tags, _lineInfo ); -return TestCase( _testCase, std::move(info) ); -} + TestCaseInfo info(static_cast(nameAndTags.name), _className, desc, tags, _lineInfo); + return TestCase(_testCase, std::move(info)); + } -void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { -std::sort(begin(tags), end(tags)); -tags.erase(std::unique(begin(tags), end(tags)), end(tags)); -testCaseInfo.lcaseTags.clear(); + void setTags(TestCaseInfo& testCaseInfo, std::vector tags) { + std::sort(begin(tags), end(tags)); + tags.erase(std::unique(begin(tags), end(tags)), end(tags)); + testCaseInfo.lcaseTags.clear(); -for( auto const& tag : tags ) { -std::string lcaseTag = toLower( tag ); -testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); -testCaseInfo.lcaseTags.push_back( lcaseTag ); -} -testCaseInfo.tags = std::move(tags); -} + for (auto const& tag : tags) { + std::string lcaseTag = toLower(tag); + testCaseInfo.properties = + static_cast(testCaseInfo.properties | parseSpecialTag(lcaseTag)); + testCaseInfo.lcaseTags.push_back(lcaseTag); + } + testCaseInfo.tags = std::move(tags); + } -TestCaseInfo::TestCaseInfo( std::string const& _name, -std::string const& _className, -std::string const& _description, -std::vector const& _tags, -SourceLineInfo const& _lineInfo ) -: name( _name ), -className( _className ), -description( _description ), -lineInfo( _lineInfo ), -properties( None ) -{ -setTags( *this, _tags ); -} + TestCaseInfo::TestCaseInfo(std::string const& _name, std::string const& _className, std::string const& _description, + std::vector const& _tags, SourceLineInfo const& _lineInfo) + : name(_name), className(_className), description(_description), lineInfo(_lineInfo), properties(None) { + setTags(*this, _tags); + } -bool TestCaseInfo::isHidden() const { -return ( properties & IsHidden ) != 0; -} -bool TestCaseInfo::throws() const { -return ( properties & Throws ) != 0; -} -bool TestCaseInfo::okToFail() const { -return ( properties & (ShouldFail | MayFail ) ) != 0; -} -bool TestCaseInfo::expectedToFail() const { -return ( properties & (ShouldFail ) ) != 0; -} + bool TestCaseInfo::isHidden() const { return (properties & IsHidden) != 0; } + bool TestCaseInfo::throws() const { return (properties & Throws) != 0; } + bool TestCaseInfo::okToFail() const { return (properties & (ShouldFail | MayFail)) != 0; } + bool TestCaseInfo::expectedToFail() const { return (properties & (ShouldFail)) != 0; } -std::string TestCaseInfo::tagsAsString() const { -std::string ret; -// '[' and ']' per tag -std::size_t full_size = 2 * tags.size(); -for (const auto& tag : tags) { -full_size += tag.size(); -} -ret.reserve(full_size); -for (const auto& tag : tags) { -ret.push_back('['); -ret.append(tag); -ret.push_back(']'); -} + std::string TestCaseInfo::tagsAsString() const { + std::string ret; + // '[' and ']' per tag + std::size_t full_size = 2 * tags.size(); + for (const auto& tag : tags) { + full_size += tag.size(); + } + ret.reserve(full_size); + for (const auto& tag : tags) { + ret.push_back('['); + ret.append(tag); + ret.push_back(']'); + } -return ret; -} + return ret; + } -TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} + TestCase::TestCase(ITestInvoker* testCase, TestCaseInfo&& info) : TestCaseInfo(std::move(info)), test(testCase) {} -TestCase TestCase::withName( std::string const& _newName ) const { -TestCase other( *this ); -other.name = _newName; -return other; -} + TestCase TestCase::withName(std::string const& _newName) const { + TestCase other(*this); + other.name = _newName; + return other; + } -void TestCase::invoke() const { -test->invoke(); -} + void TestCase::invoke() const { test->invoke(); } -bool TestCase::operator == ( TestCase const& other ) const { -return test.get() == other.test.get() && -name == other.name && -className == other.className; -} + bool TestCase::operator==(TestCase const& other) const { + return test.get() == other.test.get() && name == other.name && className == other.className; + } -bool TestCase::operator < ( TestCase const& other ) const { -return name < other.name; -} + bool TestCase::operator<(TestCase const& other) const { return name < other.name; } -TestCaseInfo const& TestCase::getTestCaseInfo() const -{ -return *this; -} + TestCaseInfo const& TestCase::getTestCaseInfo() const { return *this; } } // end namespace Catch // end catch_test_case_info.cpp @@ -13952,102 +13362,97 @@ return *this; namespace Catch { -std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + std::vector sortTests(IConfig const& config, std::vector const& unsortedTestCases) { -std::vector sorted = unsortedTestCases; + std::vector sorted = unsortedTestCases; -switch( config.runOrder() ) { -case RunTests::InLexicographicalOrder: -std::sort( sorted.begin(), sorted.end() ); -break; -case RunTests::InRandomOrder: -seedRng( config ); -std::shuffle( sorted.begin(), sorted.end(), rng() ); -break; -case RunTests::InDeclarationOrder: -// already in declaration order -break; -} -return sorted; -} + switch (config.runOrder()) { + case RunTests::InLexicographicalOrder: std::sort(sorted.begin(), sorted.end()); break; + case RunTests::InRandomOrder: + seedRng(config); + std::shuffle(sorted.begin(), sorted.end(), rng()); + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } -bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { -return !testCase.throws() || config.allowThrows(); -} + bool isThrowSafe(TestCase const& testCase, IConfig const& config) { + return !testCase.throws() || config.allowThrows(); + } -bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { -return testSpec.matches( testCase ) && isThrowSafe( testCase, config ); -} + bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config) { + return testSpec.matches(testCase) && isThrowSafe(testCase, config); + } -void enforceNoDuplicateTestCases( std::vector const& functions ) { -std::set seenFunctions; -for( auto const& function : functions ) { -auto prev = seenFunctions.insert( function ); -CATCH_ENFORCE( prev.second, -"error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" -<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" -<< "\tRedefined at " << function.getTestCaseInfo().lineInfo ); -} -} + void enforceNoDuplicateTestCases(std::vector const& functions) { + std::set seenFunctions; + for (auto const& function : functions) { + auto prev = seenFunctions.insert(function); + CATCH_ENFORCE(prev.second, "error: TEST_CASE( \"" + << function.name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << function.getTestCaseInfo().lineInfo); + } + } -std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { -std::vector filtered; -filtered.reserve( testCases.size() ); -for (auto const& testCase : testCases) { -if ((!testSpec.hasFilters() && !testCase.isHidden()) || -(testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { -filtered.push_back(testCase); -} -} -return filtered; -} -std::vector const& getAllTestCasesSorted( IConfig const& config ) { -return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); -} + std::vector filterTests(std::vector const& testCases, TestSpec const& testSpec, + IConfig const& config) { + std::vector filtered; + filtered.reserve(testCases.size()); + for (auto const& testCase : testCases) { + if ((!testSpec.hasFilters() && !testCase.isHidden()) || + (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { + filtered.push_back(testCase); + } + } + return filtered; + } + std::vector const& getAllTestCasesSorted(IConfig const& config) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted(config); + } -void TestRegistry::registerTest( TestCase const& testCase ) { -std::string name = testCase.getTestCaseInfo().name; -if( name.empty() ) { -ReusableStringStream rss; -rss << "Anonymous test case " << ++m_unnamedCount; -return registerTest( testCase.withName( rss.str() ) ); -} -m_functions.push_back( testCase ); -} + void TestRegistry::registerTest(TestCase const& testCase) { + std::string name = testCase.getTestCaseInfo().name; + if (name.empty()) { + ReusableStringStream rss; + rss << "Anonymous test case " << ++m_unnamedCount; + return registerTest(testCase.withName(rss.str())); + } + m_functions.push_back(testCase); + } -std::vector const& TestRegistry::getAllTests() const { -return m_functions; -} -std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { -if( m_sortedFunctions.empty() ) -enforceNoDuplicateTestCases( m_functions ); + std::vector const& TestRegistry::getAllTests() const { return m_functions; } + std::vector const& TestRegistry::getAllTestsSorted(IConfig const& config) const { + if (m_sortedFunctions.empty()) + enforceNoDuplicateTestCases(m_functions); -if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { -m_sortedFunctions = sortTests( config, m_functions ); -m_currentSortOrder = config.runOrder(); -} -return m_sortedFunctions; -} + if (m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty()) { + m_sortedFunctions = sortTests(config, m_functions); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } -/////////////////////////////////////////////////////////////////////////// -TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} + /////////////////////////////////////////////////////////////////////////// + TestInvokerAsFunction::TestInvokerAsFunction(void (*testAsFunction)()) noexcept + : m_testAsFunction(testAsFunction) {} -void TestInvokerAsFunction::invoke() const { -m_testAsFunction(); -} + void TestInvokerAsFunction::invoke() const { m_testAsFunction(); } -std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { -std::string className(classOrQualifiedMethodName); -if( startsWith( className, '&' ) ) -{ -std::size_t lastColons = className.rfind( "::" ); -std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); -if( penultimateColons == std::string::npos ) -penultimateColons = 1; -className = className.substr( penultimateColons, lastColons-penultimateColons ); -} -return className; -} + std::string extractClassName(StringRef const& classOrQualifiedMethodName) { + std::string className(classOrQualifiedMethodName); + if (startsWith(className, '&')) { + std::size_t lastColons = className.rfind("::"); + std::size_t penultimateColons = className.rfind("::", lastColons - 1); + if (penultimateColons == std::string::npos) + penultimateColons = 1; + className = className.substr(penultimateColons, lastColons - penultimateColons); + } + return className; + } } // end namespace Catch // end catch_test_case_registry_impl.cpp @@ -14055,348 +13460,291 @@ return className; #include #include -#include #include #include +#include #if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wexit-time-destructors" #endif namespace Catch { -namespace TestCaseTracking { + namespace TestCaseTracking { -NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) -: name( _name ), -location( _location ) -{} + NameAndLocation::NameAndLocation(std::string const& _name, SourceLineInfo const& _location) + : name(_name), location(_location) {} -ITracker::~ITracker() = default; + ITracker::~ITracker() = default; -ITracker& TrackerContext::startRun() { -m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); -m_currentTracker = nullptr; -m_runState = Executing; -return *m_rootTracker; -} + ITracker& TrackerContext::startRun() { + m_rootTracker = + std::make_shared(NameAndLocation("{root}", CATCH_INTERNAL_LINEINFO), *this, nullptr); + m_currentTracker = nullptr; + m_runState = Executing; + return *m_rootTracker; + } -void TrackerContext::endRun() { -m_rootTracker.reset(); -m_currentTracker = nullptr; -m_runState = NotStarted; -} + void TrackerContext::endRun() { + m_rootTracker.reset(); + m_currentTracker = nullptr; + m_runState = NotStarted; + } -void TrackerContext::startCycle() { -m_currentTracker = m_rootTracker.get(); -m_runState = Executing; -} -void TrackerContext::completeCycle() { -m_runState = CompletedCycle; -} + void TrackerContext::startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void TrackerContext::completeCycle() { m_runState = CompletedCycle; } -bool TrackerContext::completedCycle() const { -return m_runState == CompletedCycle; -} -ITracker& TrackerContext::currentTracker() { -return *m_currentTracker; -} -void TrackerContext::setCurrentTracker( ITracker* tracker ) { -m_currentTracker = tracker; -} + bool TrackerContext::completedCycle() const { return m_runState == CompletedCycle; } + ITracker& TrackerContext::currentTracker() { return *m_currentTracker; } + void TrackerContext::setCurrentTracker(ITracker* tracker) { m_currentTracker = tracker; } -TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) -: m_nameAndLocation( nameAndLocation ), -m_ctx( ctx ), -m_parent( parent ) -{} + TrackerBase::TrackerBase(NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent) + : m_nameAndLocation(nameAndLocation), m_ctx(ctx), m_parent(parent) {} -NameAndLocation const& TrackerBase::nameAndLocation() const { -return m_nameAndLocation; -} -bool TrackerBase::isComplete() const { -return m_runState == CompletedSuccessfully || m_runState == Failed; -} -bool TrackerBase::isSuccessfullyCompleted() const { -return m_runState == CompletedSuccessfully; -} -bool TrackerBase::isOpen() const { -return m_runState != NotStarted && !isComplete(); -} -bool TrackerBase::hasChildren() const { -return !m_children.empty(); -} + NameAndLocation const& TrackerBase::nameAndLocation() const { return m_nameAndLocation; } + bool TrackerBase::isComplete() const { return m_runState == CompletedSuccessfully || m_runState == Failed; } + bool TrackerBase::isSuccessfullyCompleted() const { return m_runState == CompletedSuccessfully; } + bool TrackerBase::isOpen() const { return m_runState != NotStarted && !isComplete(); } + bool TrackerBase::hasChildren() const { return !m_children.empty(); } -void TrackerBase::addChild( ITrackerPtr const& child ) { -m_children.push_back( child ); -} + void TrackerBase::addChild(ITrackerPtr const& child) { m_children.push_back(child); } -ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { -auto it = std::find_if( m_children.begin(), m_children.end(), -[&nameAndLocation]( ITrackerPtr const& tracker ){ -return -tracker->nameAndLocation().location == nameAndLocation.location && -tracker->nameAndLocation().name == nameAndLocation.name; -} ); -return( it != m_children.end() ) -? *it -: nullptr; -} -ITracker& TrackerBase::parent() { -assert( m_parent ); // Should always be non-null except for root -return *m_parent; -} + ITrackerPtr TrackerBase::findChild(NameAndLocation const& nameAndLocation) { + auto it = + std::find_if(m_children.begin(), m_children.end(), [&nameAndLocation](ITrackerPtr const& tracker) { + return tracker->nameAndLocation().location == nameAndLocation.location && + tracker->nameAndLocation().name == nameAndLocation.name; + }); + return (it != m_children.end()) ? *it : nullptr; + } + ITracker& TrackerBase::parent() { + assert(m_parent); // Should always be non-null except for root + return *m_parent; + } -void TrackerBase::openChild() { -if( m_runState != ExecutingChildren ) { -m_runState = ExecutingChildren; -if( m_parent ) -m_parent->openChild(); -} -} + void TrackerBase::openChild() { + if (m_runState != ExecutingChildren) { + m_runState = ExecutingChildren; + if (m_parent) + m_parent->openChild(); + } + } -bool TrackerBase::isSectionTracker() const { return false; } -bool TrackerBase::isGeneratorTracker() const { return false; } + bool TrackerBase::isSectionTracker() const { return false; } + bool TrackerBase::isGeneratorTracker() const { return false; } -void TrackerBase::open() { -m_runState = Executing; -moveToThis(); -if( m_parent ) -m_parent->openChild(); -} + void TrackerBase::open() { + m_runState = Executing; + moveToThis(); + if (m_parent) + m_parent->openChild(); + } -void TrackerBase::close() { + void TrackerBase::close() { -// Close any still open children (e.g. generators) -while( &m_ctx.currentTracker() != this ) -m_ctx.currentTracker().close(); + // Close any still open children (e.g. generators) + while (&m_ctx.currentTracker() != this) + m_ctx.currentTracker().close(); -switch( m_runState ) { -case NeedsAnotherRun: -break; + switch (m_runState) { + case NeedsAnotherRun: break; -case Executing: -m_runState = CompletedSuccessfully; -break; -case ExecutingChildren: -if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) ) -m_runState = CompletedSuccessfully; -break; + case Executing: m_runState = CompletedSuccessfully; break; + case ExecutingChildren: + if (std::all_of(m_children.begin(), m_children.end(), + [](ITrackerPtr const& t) { return t->isComplete(); })) + m_runState = CompletedSuccessfully; + break; -case NotStarted: -case CompletedSuccessfully: -case Failed: -CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); + case NotStarted: + case CompletedSuccessfully: + case Failed: CATCH_INTERNAL_ERROR("Illogical state: " << m_runState); -default: -CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); -} -moveToParent(); -m_ctx.completeCycle(); -} -void TrackerBase::fail() { -m_runState = Failed; -if( m_parent ) -m_parent->markAsNeedingAnotherRun(); -moveToParent(); -m_ctx.completeCycle(); -} -void TrackerBase::markAsNeedingAnotherRun() { -m_runState = NeedsAnotherRun; -} + default: CATCH_INTERNAL_ERROR("Unknown state: " << m_runState); + } + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::fail() { + m_runState = Failed; + if (m_parent) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::markAsNeedingAnotherRun() { m_runState = NeedsAnotherRun; } -void TrackerBase::moveToParent() { -assert( m_parent ); -m_ctx.setCurrentTracker( m_parent ); -} -void TrackerBase::moveToThis() { -m_ctx.setCurrentTracker( this ); -} + void TrackerBase::moveToParent() { + assert(m_parent); + m_ctx.setCurrentTracker(m_parent); + } + void TrackerBase::moveToThis() { m_ctx.setCurrentTracker(this); } -SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) -: TrackerBase( nameAndLocation, ctx, parent ), -m_trimmed_name(trim(nameAndLocation.name)) -{ -if( parent ) { -while( !parent->isSectionTracker() ) -parent = &parent->parent(); + SectionTracker::SectionTracker(NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent) + : TrackerBase(nameAndLocation, ctx, parent), m_trimmed_name(trim(nameAndLocation.name)) { + if (parent) { + while (!parent->isSectionTracker()) + parent = &parent->parent(); -SectionTracker& parentSection = static_cast( *parent ); -addNextFilters( parentSection.m_filters ); -} -} + SectionTracker& parentSection = static_cast(*parent); + addNextFilters(parentSection.m_filters); + } + } -bool SectionTracker::isComplete() const { -bool complete = true; + bool SectionTracker::isComplete() const { + bool complete = true; -if ((m_filters.empty() || m_filters[0] == "") -|| std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { -complete = TrackerBase::isComplete(); -} -return complete; -} + if ((m_filters.empty() || m_filters[0] == "") || + std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { + complete = TrackerBase::isComplete(); + } + return complete; + } -bool SectionTracker::isSectionTracker() const { return true; } + bool SectionTracker::isSectionTracker() const { return true; } -SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { -std::shared_ptr section; + SectionTracker& SectionTracker::acquire(TrackerContext& ctx, NameAndLocation const& nameAndLocation) { + std::shared_ptr section; -ITracker& currentTracker = ctx.currentTracker(); -if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { -assert( childTracker ); -assert( childTracker->isSectionTracker() ); -section = std::static_pointer_cast( childTracker ); -} -else { -section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); -currentTracker.addChild( section ); -} -if( !ctx.completedCycle() ) -section->tryOpen(); -return *section; -} + ITracker& currentTracker = ctx.currentTracker(); + if (ITrackerPtr childTracker = currentTracker.findChild(nameAndLocation)) { + assert(childTracker); + assert(childTracker->isSectionTracker()); + section = std::static_pointer_cast(childTracker); + } else { + section = std::make_shared(nameAndLocation, ctx, ¤tTracker); + currentTracker.addChild(section); + } + if (!ctx.completedCycle()) + section->tryOpen(); + return *section; + } -void SectionTracker::tryOpen() { -if( !isComplete() ) -open(); -} + void SectionTracker::tryOpen() { + if (!isComplete()) + open(); + } -void SectionTracker::addInitialFilters( std::vector const& filters ) { -if( !filters.empty() ) { -m_filters.reserve( m_filters.size() + filters.size() + 2 ); -m_filters.push_back(""); // Root - should never be consulted -m_filters.push_back(""); // Test Case - not a section filter -m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); -} -} -void SectionTracker::addNextFilters( std::vector const& filters ) { -if( filters.size() > 1 ) -m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); -} + void SectionTracker::addInitialFilters(std::vector const& filters) { + if (!filters.empty()) { + m_filters.reserve(m_filters.size() + filters.size() + 2); + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + m_filters.insert(m_filters.end(), filters.begin(), filters.end()); + } + } + void SectionTracker::addNextFilters(std::vector const& filters) { + if (filters.size() > 1) + m_filters.insert(m_filters.end(), filters.begin() + 1, filters.end()); + } -} // namespace TestCaseTracking + } // namespace TestCaseTracking -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; + using TestCaseTracking::ITracker; + using TestCaseTracking::SectionTracker; + using TestCaseTracking::TrackerContext; } // namespace Catch #if defined(__clang__) -# pragma clang diagnostic pop +#pragma clang diagnostic pop #endif // end catch_test_case_tracker.cpp // start catch_test_registry.cpp namespace Catch { -auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { -return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); -} + auto makeTestInvoker(void (*testAsFunction)()) noexcept -> ITestInvoker* { + return new (std::nothrow) TestInvokerAsFunction(testAsFunction); + } -NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + NameAndTags::NameAndTags(StringRef const& name_, StringRef const& tags_) noexcept : name(name_), tags(tags_) {} -AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { -CATCH_TRY { -getMutableRegistryHub() -.registerTest( -makeTestCase( -invoker, -extractClassName( classOrMethod ), -nameAndTags, -lineInfo)); -} CATCH_CATCH_ALL { -// Do not throw when constructing global objects, instead register the exception to be processed later -getMutableRegistryHub().registerStartupException(); -} -} + AutoReg::AutoReg(ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, + NameAndTags const& nameAndTags) noexcept { + CATCH_TRY { + getMutableRegistryHub().registerTest( + makeTestCase(invoker, extractClassName(classOrMethod), nameAndTags, lineInfo)); + } + CATCH_CATCH_ALL { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } -AutoReg::~AutoReg() = default; + AutoReg::~AutoReg() = default; } // end catch_test_registry.cpp // start catch_test_spec.cpp #include +#include #include #include -#include namespace Catch { -TestSpec::Pattern::Pattern( std::string const& name ) -: m_name( name ) -{} + TestSpec::Pattern::Pattern(std::string const& name) : m_name(name) {} -TestSpec::Pattern::~Pattern() = default; + TestSpec::Pattern::~Pattern() = default; -std::string const& TestSpec::Pattern::name() const { -return m_name; -} + std::string const& TestSpec::Pattern::name() const { return m_name; } -TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString ) -: Pattern( filterString ) -, m_wildcardPattern( toLower( name ), CaseSensitive::No ) -{} + TestSpec::NamePattern::NamePattern(std::string const& name, std::string const& filterString) + : Pattern(filterString), m_wildcardPattern(toLower(name), CaseSensitive::No) {} -bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { -return m_wildcardPattern.matches( testCase.name ); -} + bool TestSpec::NamePattern::matches(TestCaseInfo const& testCase) const { + return m_wildcardPattern.matches(testCase.name); + } -TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString ) -: Pattern( filterString ) -, m_tag( toLower( tag ) ) -{} + TestSpec::TagPattern::TagPattern(std::string const& tag, std::string const& filterString) + : Pattern(filterString), m_tag(toLower(tag)) {} -bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { -return std::find(begin(testCase.lcaseTags), -end(testCase.lcaseTags), -m_tag) != end(testCase.lcaseTags); -} + bool TestSpec::TagPattern::matches(TestCaseInfo const& testCase) const { + return std::find(begin(testCase.lcaseTags), end(testCase.lcaseTags), m_tag) != end(testCase.lcaseTags); + } -TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) -: Pattern( underlyingPattern->name() ) -, m_underlyingPattern( underlyingPattern ) -{} + TestSpec::ExcludedPattern::ExcludedPattern(PatternPtr const& underlyingPattern) + : Pattern(underlyingPattern->name()), m_underlyingPattern(underlyingPattern) {} -bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { -return !m_underlyingPattern->matches( testCase ); -} + bool TestSpec::ExcludedPattern::matches(TestCaseInfo const& testCase) const { + return !m_underlyingPattern->matches(testCase); + } -bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { -return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } ); -} + bool TestSpec::Filter::matches(TestCaseInfo const& testCase) const { + return std::all_of(m_patterns.begin(), m_patterns.end(), + [&](PatternPtr const& p) { return p->matches(testCase); }); + } -std::string TestSpec::Filter::name() const { -std::string name; -for( auto const& p : m_patterns ) -name += p->name(); -return name; -} + std::string TestSpec::Filter::name() const { + std::string name; + for (auto const& p : m_patterns) + name += p->name(); + return name; + } -bool TestSpec::hasFilters() const { -return !m_filters.empty(); -} + bool TestSpec::hasFilters() const { return !m_filters.empty(); } -bool TestSpec::matches( TestCaseInfo const& testCase ) const { -return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); -} + bool TestSpec::matches(TestCaseInfo const& testCase) const { + return std::any_of(m_filters.begin(), m_filters.end(), [&](Filter const& f) { return f.matches(testCase); }); + } -TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const -{ -Matches matches( m_filters.size() ); -std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ -std::vector currentMatches; -for( auto const& test : testCases ) -if( isThrowSafe( test, config ) && filter.matches( test ) ) -currentMatches.emplace_back( &test ); -return FilterMatch{ filter.name(), currentMatches }; -} ); -return matches; -} + TestSpec::Matches TestSpec::matchesByFilter(std::vector const& testCases, IConfig const& config) const { + Matches matches(m_filters.size()); + std::transform(m_filters.begin(), m_filters.end(), matches.begin(), [&](Filter const& filter) { + std::vector currentMatches; + for (auto const& test : testCases) + if (isThrowSafe(test, config) && filter.matches(test)) + currentMatches.emplace_back(&test); + return FilterMatch{filter.name(), currentMatches}; + }); + return matches; + } -const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{ -return (m_invalidArgs); -} + const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const { return (m_invalidArgs); } } // end catch_test_spec.cpp @@ -14404,230 +13752,202 @@ return (m_invalidArgs); namespace Catch { -TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + TestSpecParser::TestSpecParser(ITagAliasRegistry const& tagAliases) : m_tagAliases(&tagAliases) {} -TestSpecParser& TestSpecParser::parse( std::string const& arg ) { -m_mode = None; -m_exclusion = false; -m_arg = m_tagAliases->expandAliases( arg ); -m_escapeChars.clear(); -m_substring.reserve(m_arg.size()); -m_patternName.reserve(m_arg.size()); -m_realPatternPos = 0; + TestSpecParser& TestSpecParser::parse(std::string const& arg) { + m_mode = None; + m_exclusion = false; + m_arg = m_tagAliases->expandAliases(arg); + m_escapeChars.clear(); + m_substring.reserve(m_arg.size()); + m_patternName.reserve(m_arg.size()); + m_realPatternPos = 0; -for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) -//if visitChar fails -if( !visitChar( m_arg[m_pos] ) ){ -m_testSpec.m_invalidArgs.push_back(arg); -break; -} -endMode(); -return *this; -} -TestSpec TestSpecParser::testSpec() { -addFilter(); -return m_testSpec; -} -bool TestSpecParser::visitChar( char c ) { -if( (m_mode != EscapedName) && (c == '\\') ) { -escape(); -addCharToPattern(c); -return true; -}else if((m_mode != EscapedName) && (c == ',') ) { -return separate(); -} + for (m_pos = 0; m_pos < m_arg.size(); ++m_pos) + // if visitChar fails + if (!visitChar(m_arg[m_pos])) { + m_testSpec.m_invalidArgs.push_back(arg); + break; + } + endMode(); + return *this; + } + TestSpec TestSpecParser::testSpec() { + addFilter(); + return m_testSpec; + } + bool TestSpecParser::visitChar(char c) { + if ((m_mode != EscapedName) && (c == '\\')) { + escape(); + addCharToPattern(c); + return true; + } else if ((m_mode != EscapedName) && (c == ',')) { + return separate(); + } -switch( m_mode ) { -case None: -if( processNoneChar( c ) ) -return true; -break; -case Name: -processNameChar( c ); -break; -case EscapedName: -endMode(); -addCharToPattern(c); -return true; -default: -case Tag: -case QuotedName: -if( processOtherChar( c ) ) -return true; -break; -} + switch (m_mode) { + case None: + if (processNoneChar(c)) + return true; + break; + case Name: processNameChar(c); break; + case EscapedName: + endMode(); + addCharToPattern(c); + return true; + default: + case Tag: + case QuotedName: + if (processOtherChar(c)) + return true; + break; + } -m_substring += c; -if( !isControlChar( c ) ) { -m_patternName += c; -m_realPatternPos++; -} -return true; -} -// Two of the processing methods return true to signal the caller to return -// without adding the given character to the current pattern strings -bool TestSpecParser::processNoneChar( char c ) { -switch( c ) { -case ' ': -return true; -case '~': -m_exclusion = true; -return false; -case '[': -startNewMode( Tag ); -return false; -case '"': -startNewMode( QuotedName ); -return false; -default: -startNewMode( Name ); -return false; -} -} -void TestSpecParser::processNameChar( char c ) { -if( c == '[' ) { -if( m_substring == "exclude:" ) -m_exclusion = true; -else -endMode(); -startNewMode( Tag ); -} -} -bool TestSpecParser::processOtherChar( char c ) { -if( !isControlChar( c ) ) -return false; -m_substring += c; -endMode(); -return true; -} -void TestSpecParser::startNewMode( Mode mode ) { -m_mode = mode; -} -void TestSpecParser::endMode() { -switch( m_mode ) { -case Name: -case QuotedName: -return addNamePattern(); -case Tag: -return addTagPattern(); -case EscapedName: -revertBackToLastMode(); -return; -case None: -default: -return startNewMode( None ); -} -} -void TestSpecParser::escape() { -saveLastMode(); -m_mode = EscapedName; -m_escapeChars.push_back(m_realPatternPos); -} -bool TestSpecParser::isControlChar( char c ) const { -switch( m_mode ) { -default: -return false; -case None: -return c == '~'; -case Name: -return c == '['; -case EscapedName: -return true; -case QuotedName: -return c == '"'; -case Tag: -return c == '[' || c == ']'; -} -} + m_substring += c; + if (!isControlChar(c)) { + m_patternName += c; + m_realPatternPos++; + } + return true; + } + // Two of the processing methods return true to signal the caller to return + // without adding the given character to the current pattern strings + bool TestSpecParser::processNoneChar(char c) { + switch (c) { + case ' ': return true; + case '~': m_exclusion = true; return false; + case '[': startNewMode(Tag); return false; + case '"': startNewMode(QuotedName); return false; + default: startNewMode(Name); return false; + } + } + void TestSpecParser::processNameChar(char c) { + if (c == '[') { + if (m_substring == "exclude:") + m_exclusion = true; + else + endMode(); + startNewMode(Tag); + } + } + bool TestSpecParser::processOtherChar(char c) { + if (!isControlChar(c)) + return false; + m_substring += c; + endMode(); + return true; + } + void TestSpecParser::startNewMode(Mode mode) { m_mode = mode; } + void TestSpecParser::endMode() { + switch (m_mode) { + case Name: + case QuotedName: return addNamePattern(); + case Tag: return addTagPattern(); + case EscapedName: revertBackToLastMode(); return; + case None: + default: return startNewMode(None); + } + } + void TestSpecParser::escape() { + saveLastMode(); + m_mode = EscapedName; + m_escapeChars.push_back(m_realPatternPos); + } + bool TestSpecParser::isControlChar(char c) const { + switch (m_mode) { + default: return false; + case None: return c == '~'; + case Name: return c == '['; + case EscapedName: return true; + case QuotedName: return c == '"'; + case Tag: return c == '[' || c == ']'; + } + } -void TestSpecParser::addFilter() { -if( !m_currentFilter.m_patterns.empty() ) { -m_testSpec.m_filters.push_back( m_currentFilter ); -m_currentFilter = TestSpec::Filter(); -} -} + void TestSpecParser::addFilter() { + if (!m_currentFilter.m_patterns.empty()) { + m_testSpec.m_filters.push_back(m_currentFilter); + m_currentFilter = TestSpec::Filter(); + } + } -void TestSpecParser::saveLastMode() { -lastMode = m_mode; -} + void TestSpecParser::saveLastMode() { lastMode = m_mode; } -void TestSpecParser::revertBackToLastMode() { -m_mode = lastMode; -} + void TestSpecParser::revertBackToLastMode() { m_mode = lastMode; } -bool TestSpecParser::separate() { -if( (m_mode==QuotedName) || (m_mode==Tag) ){ -//invalid argument, signal failure to previous scope. -m_mode = None; -m_pos = m_arg.size(); -m_substring.clear(); -m_patternName.clear(); -return false; -} -endMode(); -addFilter(); -return true; //success -} + bool TestSpecParser::separate() { + if ((m_mode == QuotedName) || (m_mode == Tag)) { + // invalid argument, signal failure to previous scope. + m_mode = None; + m_pos = m_arg.size(); + m_substring.clear(); + m_patternName.clear(); + return false; + } + endMode(); + addFilter(); + return true; // success + } -std::string TestSpecParser::preprocessPattern() { -std::string token = m_patternName; -for (std::size_t i = 0; i < m_escapeChars.size(); ++i) -token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); -m_escapeChars.clear(); -if (startsWith(token, "exclude:")) { -m_exclusion = true; -token = token.substr(8); -} + std::string TestSpecParser::preprocessPattern() { + std::string token = m_patternName; + for (std::size_t i = 0; i < m_escapeChars.size(); ++i) + token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); + m_escapeChars.clear(); + if (startsWith(token, "exclude:")) { + m_exclusion = true; + token = token.substr(8); + } -m_patternName.clear(); + m_patternName.clear(); -return token; -} + return token; + } -void TestSpecParser::addNamePattern() { -auto token = preprocessPattern(); + void TestSpecParser::addNamePattern() { + auto token = preprocessPattern(); -if (!token.empty()) { -TestSpec::PatternPtr pattern = std::make_shared(token, m_substring); -if (m_exclusion) -pattern = std::make_shared(pattern); -m_currentFilter.m_patterns.push_back(pattern); -} -m_substring.clear(); -m_exclusion = false; -m_mode = None; -} + if (!token.empty()) { + TestSpec::PatternPtr pattern = std::make_shared(token, m_substring); + if (m_exclusion) + pattern = std::make_shared(pattern); + m_currentFilter.m_patterns.push_back(pattern); + } + m_substring.clear(); + m_exclusion = false; + m_mode = None; + } -void TestSpecParser::addTagPattern() { -auto token = preprocessPattern(); + void TestSpecParser::addTagPattern() { + auto token = preprocessPattern(); -if (!token.empty()) { -// If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) -// we have to create a separate hide tag and shorten the real one -if (token.size() > 1 && token[0] == '.') { -token.erase(token.begin()); -TestSpec::PatternPtr pattern = std::make_shared(".", m_substring); -if (m_exclusion) { -pattern = std::make_shared(pattern); -} -m_currentFilter.m_patterns.push_back(pattern); -} + if (!token.empty()) { + // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) + // we have to create a separate hide tag and shorten the real one + if (token.size() > 1 && token[0] == '.') { + token.erase(token.begin()); + TestSpec::PatternPtr pattern = std::make_shared(".", m_substring); + if (m_exclusion) { + pattern = std::make_shared(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); + } -TestSpec::PatternPtr pattern = std::make_shared(token, m_substring); + TestSpec::PatternPtr pattern = std::make_shared(token, m_substring); -if (m_exclusion) { -pattern = std::make_shared(pattern); -} -m_currentFilter.m_patterns.push_back(pattern); -} -m_substring.clear(); -m_exclusion = false; -m_mode = None; -} + if (m_exclusion) { + pattern = std::make_shared(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); + } + m_substring.clear(); + m_exclusion = false; + m_mode = None; + } -TestSpec parseTestSpec( std::string const& arg ) { -return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); -} + TestSpec parseTestSpec(std::string const& arg) { + return TestSpecParser(ITagAliasRegistry::get()).parse(arg).testSpec(); + } } // namespace Catch // end catch_test_spec_parser.cpp @@ -14639,70 +13959,64 @@ static const uint64_t nanosecondsInSecond = 1000000000; namespace Catch { -auto getCurrentNanosecondsSinceEpoch() -> uint64_t { -return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); -} + auto getCurrentNanosecondsSinceEpoch() -> uint64_t { + return std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()) + .count(); + } -namespace { -auto estimateClockResolution() -> uint64_t { -uint64_t sum = 0; -static const uint64_t iterations = 1000000; + namespace { + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; -auto startTime = getCurrentNanosecondsSinceEpoch(); + auto startTime = getCurrentNanosecondsSinceEpoch(); -for( std::size_t i = 0; i < iterations; ++i ) { + for (std::size_t i = 0; i < iterations; ++i) { -uint64_t ticks; -uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); -do { -ticks = getCurrentNanosecondsSinceEpoch(); -} while( ticks == baseTicks ); + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } while (ticks == baseTicks); -auto delta = ticks - baseTicks; -sum += delta; + auto delta = ticks - baseTicks; + sum += delta; -// If we have been calibrating for over 3 seconds -- the clock -// is terrible and we should move on. -// TBD: How to signal that the measured resolution is probably wrong? -if (ticks > startTime + 3 * nanosecondsInSecond) { -return sum / ( i + 1u ); -} -} + // If we have been calibrating for over 3 seconds -- the clock + // is terrible and we should move on. + // TBD: How to signal that the measured resolution is probably wrong? + if (ticks > startTime + 3 * nanosecondsInSecond) { + return sum / (i + 1u); + } + } -// We're just taking the mean, here. To do better we could take the std. dev and exclude outliers -// - and potentially do more iterations if there's a high variance. -return sum/iterations; -} -} -auto getEstimatedClockResolution() -> uint64_t { -static auto s_resolution = estimateClockResolution(); -return s_resolution; -} + // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers + // - and potentially do more iterations if there's a high variance. + return sum / iterations; + } + } + auto getEstimatedClockResolution() -> uint64_t { + static auto s_resolution = estimateClockResolution(); + return s_resolution; + } -void Timer::start() { -m_nanoseconds = getCurrentNanosecondsSinceEpoch(); -} -auto Timer::getElapsedNanoseconds() const -> uint64_t { -return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; -} -auto Timer::getElapsedMicroseconds() const -> uint64_t { -return getElapsedNanoseconds()/1000; -} -auto Timer::getElapsedMilliseconds() const -> unsigned int { -return static_cast(getElapsedMicroseconds()/1000); -} -auto Timer::getElapsedSeconds() const -> double { -return getElapsedMicroseconds()/1000000.0; -} + void Timer::start() { m_nanoseconds = getCurrentNanosecondsSinceEpoch(); } + auto Timer::getElapsedNanoseconds() const -> uint64_t { return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; } + auto Timer::getElapsedMicroseconds() const -> uint64_t { return getElapsedNanoseconds() / 1000; } + auto Timer::getElapsedMilliseconds() const -> unsigned int { + return static_cast(getElapsedMicroseconds() / 1000); + } + auto Timer::getElapsedSeconds() const -> double { return getElapsedMicroseconds() / 1000000.0; } } // namespace Catch // end catch_timer.cpp // start catch_tostring.cpp #if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -# pragma clang diagnostic ignored "-Wglobal-constructors" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wglobal-constructors" #endif // Enable specific decls locally @@ -14715,237 +14029,218 @@ return getElapsedMicroseconds()/1000000.0; namespace Catch { -namespace Detail { + namespace Detail { -const std::string unprintableString = "{?}"; + const std::string unprintableString = "{?}"; -namespace { -const int hexThreshold = 255; + namespace { + const int hexThreshold = 255; -struct Endianness { -enum Arch { Big, Little }; + struct Endianness { + enum Arch { Big, Little }; -static Arch which() { -int one = 1; -// If the lowest byte we read is non-zero, we can assume -// that little endian format is used. -auto value = *reinterpret_cast(&one); -return value ? Little : Big; -} -}; -} + static Arch which() { + int one = 1; + // If the lowest byte we read is non-zero, we can assume + // that little endian format is used. + auto value = *reinterpret_cast(&one); + return value ? Little : Big; + } + }; + } -std::string rawMemoryToString( const void *object, std::size_t size ) { -// Reverse order for little endian architectures -int i = 0, end = static_cast( size ), inc = 1; -if( Endianness::which() == Endianness::Little ) { -i = end-1; -end = inc = -1; -} + std::string rawMemoryToString(const void* object, std::size_t size) { + // Reverse order for little endian architectures + int i = 0, end = static_cast(size), inc = 1; + if (Endianness::which() == Endianness::Little) { + i = end - 1; + end = inc = -1; + } -unsigned char const *bytes = static_cast(object); -ReusableStringStream rss; -rss << "0x" << std::setfill('0') << std::hex; -for( ; i != end; i += inc ) -rss << std::setw(2) << static_cast(bytes[i]); -return rss.str(); -} -} + unsigned char const* bytes = static_cast(object); + ReusableStringStream rss; + rss << "0x" << std::setfill('0') << std::hex; + for (; i != end; i += inc) + rss << std::setw(2) << static_cast(bytes[i]); + return rss.str(); + } + } -template -std::string fpToString( T value, int precision ) { -if (Catch::isnan(value)) { -return "nan"; -} + template std::string fpToString(T value, int precision) { + if (Catch::isnan(value)) { + return "nan"; + } -ReusableStringStream rss; -rss << std::setprecision( precision ) -<< std::fixed -<< value; -std::string d = rss.str(); -std::size_t i = d.find_last_not_of( '0' ); -if( i != std::string::npos && i != d.size()-1 ) { -if( d[i] == '.' ) -i++; -d = d.substr( 0, i+1 ); -} -return d; -} + ReusableStringStream rss; + rss << std::setprecision(precision) << std::fixed << value; + std::string d = rss.str(); + std::size_t i = d.find_last_not_of('0'); + if (i != std::string::npos && i != d.size() - 1) { + if (d[i] == '.') + i++; + d = d.substr(0, i + 1); + } + return d; + } -//// ======================================================= //// -// -// Out-of-line defs for full specialization of StringMaker -// -//// ======================================================= //// + //// ======================================================= //// + // + // Out-of-line defs for full specialization of StringMaker + // + //// ======================================================= //// -std::string StringMaker::convert(const std::string& str) { -if (!getCurrentContext().getConfig()->showInvisibles()) { -return '"' + str + '"'; -} + std::string StringMaker::convert(const std::string& str) { + if (!getCurrentContext().getConfig()->showInvisibles()) { + return '"' + str + '"'; + } -std::string s("\""); -for (char c : str) { -switch (c) { -case '\n': -s.append("\\n"); -break; -case '\t': -s.append("\\t"); -break; -default: -s.push_back(c); -break; -} -} -s.append("\""); -return s; -} + std::string s("\""); + for (char c : str) { + switch (c) { + case '\n': s.append("\\n"); break; + case '\t': s.append("\\t"); break; + default: s.push_back(c); break; + } + } + s.append("\""); + return s; + } #ifdef CATCH_CONFIG_CPP17_STRING_VIEW -std::string StringMaker::convert(std::string_view str) { -return ::Catch::Detail::stringify(std::string{ str }); -} + std::string StringMaker::convert(std::string_view str) { + return ::Catch::Detail::stringify(std::string{str}); + } #endif -std::string StringMaker::convert(char const* str) { -if (str) { -return ::Catch::Detail::stringify(std::string{ str }); -} else { -return{ "{null string}" }; -} -} -std::string StringMaker::convert(char* str) { -if (str) { -return ::Catch::Detail::stringify(std::string{ str }); -} else { -return{ "{null string}" }; -} -} + std::string StringMaker::convert(char const* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{str}); + } else { + return {"{null string}"}; + } + } + std::string StringMaker::convert(char* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{str}); + } else { + return {"{null string}"}; + } + } #ifdef CATCH_CONFIG_WCHAR -std::string StringMaker::convert(const std::wstring& wstr) { -std::string s; -s.reserve(wstr.size()); -for (auto c : wstr) { -s += (c <= 0xff) ? static_cast(c) : '?'; -} -return ::Catch::Detail::stringify(s); -} + std::string StringMaker::convert(const std::wstring& wstr) { + std::string s; + s.reserve(wstr.size()); + for (auto c : wstr) { + s += (c <= 0xff) ? static_cast(c) : '?'; + } + return ::Catch::Detail::stringify(s); + } -# ifdef CATCH_CONFIG_CPP17_STRING_VIEW -std::string StringMaker::convert(std::wstring_view str) { -return StringMaker::convert(std::wstring(str)); -} -# endif +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW + std::string StringMaker::convert(std::wstring_view str) { + return StringMaker::convert(std::wstring(str)); + } +#endif -std::string StringMaker::convert(wchar_t const * str) { -if (str) { -return ::Catch::Detail::stringify(std::wstring{ str }); -} else { -return{ "{null string}" }; -} -} -std::string StringMaker::convert(wchar_t * str) { -if (str) { -return ::Catch::Detail::stringify(std::wstring{ str }); -} else { -return{ "{null string}" }; -} -} + std::string StringMaker::convert(wchar_t const* str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{str}); + } else { + return {"{null string}"}; + } + } + std::string StringMaker::convert(wchar_t* str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{str}); + } else { + return {"{null string}"}; + } + } #endif #if defined(CATCH_CONFIG_CPP17_BYTE) #include -std::string StringMaker::convert(std::byte value) { -return ::Catch::Detail::stringify(std::to_integer(value)); -} + std::string StringMaker::convert(std::byte value) { + return ::Catch::Detail::stringify(std::to_integer(value)); + } #endif // defined(CATCH_CONFIG_CPP17_BYTE) -std::string StringMaker::convert(int value) { -return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long value) { -return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long long value) { -ReusableStringStream rss; -rss << value; -if (value > Detail::hexThreshold) { -rss << " (0x" << std::hex << value << ')'; -} -return rss.str(); -} + std::string StringMaker::convert(int value) { + return ::Catch::Detail::stringify(static_cast(value)); + } + std::string StringMaker::convert(long value) { + return ::Catch::Detail::stringify(static_cast(value)); + } + std::string StringMaker::convert(long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); + } -std::string StringMaker::convert(unsigned int value) { -return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long value) { -return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long long value) { -ReusableStringStream rss; -rss << value; -if (value > Detail::hexThreshold) { -rss << " (0x" << std::hex << value << ')'; -} -return rss.str(); -} + std::string StringMaker::convert(unsigned int value) { + return ::Catch::Detail::stringify(static_cast(value)); + } + std::string StringMaker::convert(unsigned long value) { + return ::Catch::Detail::stringify(static_cast(value)); + } + std::string StringMaker::convert(unsigned long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); + } -std::string StringMaker::convert(bool b) { -return b ? "true" : "false"; -} + std::string StringMaker::convert(bool b) { return b ? "true" : "false"; } -std::string StringMaker::convert(signed char value) { -if (value == '\r') { -return "'\\r'"; -} else if (value == '\f') { -return "'\\f'"; -} else if (value == '\n') { -return "'\\n'"; -} else if (value == '\t') { -return "'\\t'"; -} else if ('\0' <= value && value < ' ') { -return ::Catch::Detail::stringify(static_cast(value)); -} else { -char chstr[] = "' '"; -chstr[1] = value; -return chstr; -} -} -std::string StringMaker::convert(char c) { -return ::Catch::Detail::stringify(static_cast(c)); -} -std::string StringMaker::convert(unsigned char c) { -return ::Catch::Detail::stringify(static_cast(c)); -} + std::string StringMaker::convert(signed char value) { + if (value == '\r') { + return "'\\r'"; + } else if (value == '\f') { + return "'\\f'"; + } else if (value == '\n') { + return "'\\n'"; + } else if (value == '\t') { + return "'\\t'"; + } else if ('\0' <= value && value < ' ') { + return ::Catch::Detail::stringify(static_cast(value)); + } else { + char chstr[] = "' '"; + chstr[1] = value; + return chstr; + } + } + std::string StringMaker::convert(char c) { return ::Catch::Detail::stringify(static_cast(c)); } + std::string StringMaker::convert(unsigned char c) { + return ::Catch::Detail::stringify(static_cast(c)); + } -std::string StringMaker::convert(std::nullptr_t) { -return "nullptr"; -} + std::string StringMaker::convert(std::nullptr_t) { return "nullptr"; } -int StringMaker::precision = 5; + int StringMaker::precision = 5; -std::string StringMaker::convert(float value) { -return fpToString(value, precision) + 'f'; -} + std::string StringMaker::convert(float value) { return fpToString(value, precision) + 'f'; } -int StringMaker::precision = 10; + int StringMaker::precision = 10; -std::string StringMaker::convert(double value) { -return fpToString(value, precision); -} + std::string StringMaker::convert(double value) { return fpToString(value, precision); } -std::string ratio_string::symbol() { return "a"; } -std::string ratio_string::symbol() { return "f"; } -std::string ratio_string::symbol() { return "p"; } -std::string ratio_string::symbol() { return "n"; } -std::string ratio_string::symbol() { return "u"; } -std::string ratio_string::symbol() { return "m"; } + std::string ratio_string::symbol() { return "a"; } + std::string ratio_string::symbol() { return "f"; } + std::string ratio_string::symbol() { return "p"; } + std::string ratio_string::symbol() { return "n"; } + std::string ratio_string::symbol() { return "u"; } + std::string ratio_string::symbol() { return "m"; } } // end namespace Catch #if defined(__clang__) -# pragma clang diagnostic pop +#pragma clang diagnostic pop #endif // end catch_tostring.cpp @@ -14953,54 +14248,48 @@ std::string ratio_string::symbol() { return "m"; } namespace Catch { -Counts Counts::operator - ( Counts const& other ) const { -Counts diff; -diff.passed = passed - other.passed; -diff.failed = failed - other.failed; -diff.failedButOk = failedButOk - other.failedButOk; -return diff; -} + Counts Counts::operator-(Counts const& other) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } -Counts& Counts::operator += ( Counts const& other ) { -passed += other.passed; -failed += other.failed; -failedButOk += other.failedButOk; -return *this; -} + Counts& Counts::operator+=(Counts const& other) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } -std::size_t Counts::total() const { -return passed + failed + failedButOk; -} -bool Counts::allPassed() const { -return failed == 0 && failedButOk == 0; -} -bool Counts::allOk() const { -return failed == 0; -} + std::size_t Counts::total() const { return passed + failed + failedButOk; } + bool Counts::allPassed() const { return failed == 0 && failedButOk == 0; } + bool Counts::allOk() const { return failed == 0; } -Totals Totals::operator - ( Totals const& other ) const { -Totals diff; -diff.assertions = assertions - other.assertions; -diff.testCases = testCases - other.testCases; -return diff; -} + Totals Totals::operator-(Totals const& other) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } -Totals& Totals::operator += ( Totals const& other ) { -assertions += other.assertions; -testCases += other.testCases; -return *this; -} + Totals& Totals::operator+=(Totals const& other) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } -Totals Totals::delta( Totals const& prevTotals ) const { -Totals diff = *this - prevTotals; -if( diff.assertions.failed > 0 ) -++diff.testCases.failed; -else if( diff.assertions.failedButOk > 0 ) -++diff.testCases.failedButOk; -else -++diff.testCases.passed; -return diff; -} + Totals Totals::delta(Totals const& prevTotals) const { + Totals diff = *this - prevTotals; + if (diff.assertions.failed > 0) + ++diff.testCases.failed; + else if (diff.assertions.failedButOk > 0) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } } // end catch_totals.cpp @@ -15009,13 +14298,13 @@ return diff; #include namespace Catch { -bool uncaught_exceptions() { + bool uncaught_exceptions() { #if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -return std::uncaught_exceptions() > 0; + return std::uncaught_exceptions() > 0; #else -return std::uncaught_exception(); + return std::uncaught_exception(); #endif -} + } } // end namespace Catch // end catch_uncaught_exceptions.cpp // start catch_version.cpp @@ -15024,35 +14313,24 @@ return std::uncaught_exception(); namespace Catch { -Version::Version -( unsigned int _majorVersion, -unsigned int _minorVersion, -unsigned int _patchNumber, -char const * const _branchName, -unsigned int _buildNumber ) -: majorVersion( _majorVersion ), -minorVersion( _minorVersion ), -patchNumber( _patchNumber ), -branchName( _branchName ), -buildNumber( _buildNumber ) -{} + Version::Version(unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, + char const* const _branchName, unsigned int _buildNumber) + : majorVersion(_majorVersion), minorVersion(_minorVersion), patchNumber(_patchNumber), branchName(_branchName), + buildNumber(_buildNumber) {} -std::ostream& operator << ( std::ostream& os, Version const& version ) { -os << version.majorVersion << '.' -<< version.minorVersion << '.' -<< version.patchNumber; -// branchName is never null -> 0th char is \0 if it is empty -if (version.branchName[0]) { -os << '-' << version.branchName -<< '.' << version.buildNumber; -} -return os; -} + std::ostream& operator<<(std::ostream& os, Version const& version) { + os << version.majorVersion << '.' << version.minorVersion << '.' << version.patchNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName << '.' << version.buildNumber; + } + return os; + } -Version const& libraryVersion() { -static Version version( 2, 11, 0, "", 0 ); -return version; -} + Version const& libraryVersion() { + static Version version(2, 11, 0, "", 0); + return version; + } } // end catch_version.cpp @@ -15060,39 +14338,31 @@ return version; namespace Catch { -WildcardPattern::WildcardPattern( std::string const& pattern, -CaseSensitive::Choice caseSensitivity ) -: m_caseSensitivity( caseSensitivity ), -m_pattern( normaliseString( pattern ) ) -{ -if( startsWith( m_pattern, '*' ) ) { -m_pattern = m_pattern.substr( 1 ); -m_wildcard = WildcardAtStart; -} -if( endsWith( m_pattern, '*' ) ) { -m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); -m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); -} -} + WildcardPattern::WildcardPattern(std::string const& pattern, CaseSensitive::Choice caseSensitivity) + : m_caseSensitivity(caseSensitivity), m_pattern(normaliseString(pattern)) { + if (startsWith(m_pattern, '*')) { + m_pattern = m_pattern.substr(1); + m_wildcard = WildcardAtStart; + } + if (endsWith(m_pattern, '*')) { + m_pattern = m_pattern.substr(0, m_pattern.size() - 1); + m_wildcard = static_cast(m_wildcard | WildcardAtEnd); + } + } -bool WildcardPattern::matches( std::string const& str ) const { -switch( m_wildcard ) { -case NoWildcard: -return m_pattern == normaliseString( str ); -case WildcardAtStart: -return endsWith( normaliseString( str ), m_pattern ); -case WildcardAtEnd: -return startsWith( normaliseString( str ), m_pattern ); -case WildcardAtBothEnds: -return contains( normaliseString( str ), m_pattern ); -default: -CATCH_INTERNAL_ERROR( "Unknown enum" ); -} -} + bool WildcardPattern::matches(std::string const& str) const { + switch (m_wildcard) { + case NoWildcard: return m_pattern == normaliseString(str); + case WildcardAtStart: return endsWith(normaliseString(str), m_pattern); + case WildcardAtEnd: return startsWith(normaliseString(str), m_pattern); + case WildcardAtBothEnds: return contains(normaliseString(str), m_pattern); + default: CATCH_INTERNAL_ERROR("Unknown enum"); + } + } -std::string WildcardPattern::normaliseString( std::string const& str ) const { -return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str ); -} + std::string WildcardPattern::normaliseString(std::string const& str) const { + return trim(m_caseSensitivity == CaseSensitive::No ? toLower(str) : str); + } } // end catch_wildcard_pattern.cpp // start catch_xmlwriter.cpp @@ -15104,383 +14374,353 @@ using uchar = unsigned char; namespace Catch { -namespace { + namespace { -size_t trailingBytes(unsigned char c) { -if ((c & 0xE0) == 0xC0) { -return 2; -} -if ((c & 0xF0) == 0xE0) { -return 3; -} -if ((c & 0xF8) == 0xF0) { -return 4; -} -CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); -} + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } -uint32_t headerValue(unsigned char c) { -if ((c & 0xE0) == 0xC0) { -return c & 0x1F; -} -if ((c & 0xF0) == 0xE0) { -return c & 0x0F; -} -if ((c & 0xF8) == 0xF0) { -return c & 0x07; -} -CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); -} + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } -void hexEscapeChar(std::ostream& os, unsigned char c) { -std::ios_base::fmtflags f(os.flags()); -os << "\\x" -<< std::uppercase << std::hex << std::setfill('0') << std::setw(2) -<< static_cast(c); -os.flags(f); -} + void hexEscapeChar(std::ostream& os, unsigned char c) { + std::ios_base::fmtflags f(os.flags()); + os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast(c); + os.flags(f); + } -bool shouldNewline(XmlFormatting fmt) { -return !!(static_cast::type>(fmt & XmlFormatting::Newline)); -} + bool shouldNewline(XmlFormatting fmt) { + return !!(static_cast::type>(fmt & XmlFormatting::Newline)); + } -bool shouldIndent(XmlFormatting fmt) { -return !!(static_cast::type>(fmt & XmlFormatting::Indent)); -} + bool shouldIndent(XmlFormatting fmt) { + return !!(static_cast::type>(fmt & XmlFormatting::Indent)); + } -} // anonymous namespace + } // anonymous namespace -XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) { -return static_cast( -static_cast::type>(lhs) | -static_cast::type>(rhs) -); -} + XmlFormatting operator|(XmlFormatting lhs, XmlFormatting rhs) { + return static_cast(static_cast::type>(lhs) | + static_cast::type>(rhs)); + } -XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) { -return static_cast( -static_cast::type>(lhs) & -static_cast::type>(rhs) -); -} + XmlFormatting operator&(XmlFormatting lhs, XmlFormatting rhs) { + return static_cast(static_cast::type>(lhs) & + static_cast::type>(rhs)); + } -XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) -: m_str( str ), -m_forWhat( forWhat ) -{} + XmlEncode::XmlEncode(std::string const& str, ForWhat forWhat) : m_str(str), m_forWhat(forWhat) {} -void XmlEncode::encodeTo( std::ostream& os ) const { -// Apostrophe escaping not necessary if we always use " to write attributes -// (see: http://www.w3.org/TR/xml/#syntax) + void XmlEncode::encodeTo(std::ostream& os) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) -for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { -uchar c = m_str[idx]; -switch (c) { -case '<': os << "<"; break; -case '&': os << "&"; break; + for (std::size_t idx = 0; idx < m_str.size(); ++idx) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; -case '>': -// See: http://www.w3.org/TR/xml/#syntax -if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') -os << ">"; -else -os << c; -break; + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; -case '\"': -if (m_forWhat == ForAttributes) -os << """; -else -os << c; -break; + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; -default: -// Check for control characters and invalid utf-8 + default: + // Check for control characters and invalid utf-8 -// Escape control characters in standard ascii -// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 -if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { -hexEscapeChar(os, c); -break; -} + // Escape control characters in standard ascii + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } -// Plain ASCII: Write it to stream -if (c < 0x7F) { -os << c; -break; -} + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } -// UTF-8 territory -// Check if the encoding is valid and if it is not, hex escape bytes. -// Important: We do not check the exact decoded values for validity, only the encoding format -// First check that this bytes is a valid lead byte: -// This means that it is not encoded as 1111 1XXX -// Or as 10XX XXXX -if (c < 0xC0 || -c >= 0xF8) { -hexEscapeChar(os, c); -break; -} + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || c >= 0xF8) { + hexEscapeChar(os, c); + break; + } -auto encBytes = trailingBytes(c); -// Are there enough bytes left to avoid accessing out-of-bounds memory? -if (idx + encBytes - 1 >= m_str.size()) { -hexEscapeChar(os, c); -break; -} -// The header is valid, check data -// The next encBytes bytes must together be a valid utf-8 -// This means: bitpattern 10XX XXXX and the extracted value is sane (ish) -bool valid = true; -uint32_t value = headerValue(c); -for (std::size_t n = 1; n < encBytes; ++n) { -uchar nc = m_str[idx + n]; -valid &= ((nc & 0xC0) == 0x80); -value = (value << 6) | (nc & 0x3F); -} + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } -if ( -// Wrong bit pattern of following bytes -(!valid) || -// Overlong encodings -(value < 0x80) || -(0x80 <= value && value < 0x800 && encBytes > 2) || -(0x800 < value && value < 0x10000 && encBytes > 3) || -// Encoded value out of range -(value >= 0x110000) -) { -hexEscapeChar(os, c); -break; -} + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || (0x80 <= value && value < 0x800 && encBytes > 2) || + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000)) { + hexEscapeChar(os, c); + break; + } -// If we got here, this is in fact a valid(ish) utf-8 sequence -for (std::size_t n = 0; n < encBytes; ++n) { -os << m_str[idx + n]; -} -idx += encBytes - 1; -break; -} -} -} + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } -std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { -xmlEncode.encodeTo( os ); -return os; -} + std::ostream& operator<<(std::ostream& os, XmlEncode const& xmlEncode) { + xmlEncode.encodeTo(os); + return os; + } -XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt ) -: m_writer( writer ), -m_fmt(fmt) -{} + XmlWriter::ScopedElement::ScopedElement(XmlWriter* writer, XmlFormatting fmt) : m_writer(writer), m_fmt(fmt) {} -XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept -: m_writer( other.m_writer ), -m_fmt(other.m_fmt) -{ -other.m_writer = nullptr; -other.m_fmt = XmlFormatting::None; -} -XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { -if ( m_writer ) { -m_writer->endElement(); -} -m_writer = other.m_writer; -other.m_writer = nullptr; -m_fmt = other.m_fmt; -other.m_fmt = XmlFormatting::None; -return *this; -} + XmlWriter::ScopedElement::ScopedElement(ScopedElement&& other) noexcept + : m_writer(other.m_writer), m_fmt(other.m_fmt) { + other.m_writer = nullptr; + other.m_fmt = XmlFormatting::None; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=(ScopedElement&& other) noexcept { + if (m_writer) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + m_fmt = other.m_fmt; + other.m_fmt = XmlFormatting::None; + return *this; + } -XmlWriter::ScopedElement::~ScopedElement() { -if (m_writer) { -m_writer->endElement(m_fmt); -} -} + XmlWriter::ScopedElement::~ScopedElement() { + if (m_writer) { + m_writer->endElement(m_fmt); + } + } -XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) { -m_writer->writeText( text, fmt ); -return *this; -} + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText(std::string const& text, XmlFormatting fmt) { + m_writer->writeText(text, fmt); + return *this; + } -XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) -{ -writeDeclaration(); -} + XmlWriter::XmlWriter(std::ostream& os) : m_os(os) { writeDeclaration(); } -XmlWriter::~XmlWriter() { -while (!m_tags.empty()) { -endElement(); -} -newlineIfNecessary(); -} + XmlWriter::~XmlWriter() { + while (!m_tags.empty()) { + endElement(); + } + newlineIfNecessary(); + } -XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) { -ensureTagClosed(); -newlineIfNecessary(); -if (shouldIndent(fmt)) { -m_os << m_indent; -m_indent += " "; -} -m_os << '<' << name; -m_tags.push_back( name ); -m_tagIsOpen = true; -applyFormatting(fmt); -return *this; -} + XmlWriter& XmlWriter::startElement(std::string const& name, XmlFormatting fmt) { + ensureTagClosed(); + newlineIfNecessary(); + if (shouldIndent(fmt)) { + m_os << m_indent; + m_indent += " "; + } + m_os << '<' << name; + m_tags.push_back(name); + m_tagIsOpen = true; + applyFormatting(fmt); + return *this; + } -XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) { -ScopedElement scoped( this, fmt ); -startElement( name, fmt ); -return scoped; -} + XmlWriter::ScopedElement XmlWriter::scopedElement(std::string const& name, XmlFormatting fmt) { + ScopedElement scoped(this, fmt); + startElement(name, fmt); + return scoped; + } -XmlWriter& XmlWriter::endElement(XmlFormatting fmt) { -m_indent = m_indent.substr(0, m_indent.size() - 2); + XmlWriter& XmlWriter::endElement(XmlFormatting fmt) { + m_indent = m_indent.substr(0, m_indent.size() - 2); -if( m_tagIsOpen ) { -m_os << "/>"; -m_tagIsOpen = false; -} else { -newlineIfNecessary(); -if (shouldIndent(fmt)) { -m_os << m_indent; -} -m_os << ""; -} -m_os << std::flush; -applyFormatting(fmt); -m_tags.pop_back(); -return *this; -} + if (m_tagIsOpen) { + m_os << "/>"; + m_tagIsOpen = false; + } else { + newlineIfNecessary(); + if (shouldIndent(fmt)) { + m_os << m_indent; + } + m_os << ""; + } + m_os << std::flush; + applyFormatting(fmt); + m_tags.pop_back(); + return *this; + } -XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { -if( !name.empty() && !attribute.empty() ) -m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; -return *this; -} + XmlWriter& XmlWriter::writeAttribute(std::string const& name, std::string const& attribute) { + if (!name.empty() && !attribute.empty()) + m_os << ' ' << name << "=\"" << XmlEncode(attribute, XmlEncode::ForAttributes) << '"'; + return *this; + } -XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { -m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; -return *this; -} + XmlWriter& XmlWriter::writeAttribute(std::string const& name, bool attribute) { + m_os << ' ' << name << "=\"" << (attribute ? "true" : "false") << '"'; + return *this; + } -XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) { -if( !text.empty() ){ -bool tagWasOpen = m_tagIsOpen; -ensureTagClosed(); -if (tagWasOpen && shouldIndent(fmt)) { -m_os << m_indent; -} -m_os << XmlEncode( text ); -applyFormatting(fmt); -} -return *this; -} + XmlWriter& XmlWriter::writeText(std::string const& text, XmlFormatting fmt) { + if (!text.empty()) { + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if (tagWasOpen && shouldIndent(fmt)) { + m_os << m_indent; + } + m_os << XmlEncode(text); + applyFormatting(fmt); + } + return *this; + } -XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) { -ensureTagClosed(); -if (shouldIndent(fmt)) { -m_os << m_indent; -} -m_os << ""; -applyFormatting(fmt); -return *this; -} + XmlWriter& XmlWriter::writeComment(std::string const& text, XmlFormatting fmt) { + ensureTagClosed(); + if (shouldIndent(fmt)) { + m_os << m_indent; + } + m_os << ""; + applyFormatting(fmt); + return *this; + } -void XmlWriter::writeStylesheetRef( std::string const& url ) { -m_os << "\n"; -} + void XmlWriter::writeStylesheetRef(std::string const& url) { + m_os << "\n"; + } -XmlWriter& XmlWriter::writeBlankLine() { -ensureTagClosed(); -m_os << '\n'; -return *this; -} + XmlWriter& XmlWriter::writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } -void XmlWriter::ensureTagClosed() { -if( m_tagIsOpen ) { -m_os << '>' << std::flush; -newlineIfNecessary(); -m_tagIsOpen = false; -} -} + void XmlWriter::ensureTagClosed() { + if (m_tagIsOpen) { + m_os << '>' << std::flush; + newlineIfNecessary(); + m_tagIsOpen = false; + } + } -void XmlWriter::applyFormatting(XmlFormatting fmt) { -m_needsNewline = shouldNewline(fmt); -} + void XmlWriter::applyFormatting(XmlFormatting fmt) { m_needsNewline = shouldNewline(fmt); } -void XmlWriter::writeDeclaration() { -m_os << "\n"; -} + void XmlWriter::writeDeclaration() { m_os << "\n"; } -void XmlWriter::newlineIfNecessary() { -if( m_needsNewline ) { -m_os << std::endl; -m_needsNewline = false; -} -} + void XmlWriter::newlineIfNecessary() { + if (m_needsNewline) { + m_os << std::endl; + m_needsNewline = false; + } + } } // end catch_xmlwriter.cpp // start catch_reporter_bases.cpp -#include +#include #include #include -#include +#include #include namespace Catch { -void prepareExpandedExpression(AssertionResult& result) { -result.getExpandedExpression(); -} + void prepareExpandedExpression(AssertionResult& result) { result.getExpandedExpression(); } -// Because formatting using c++ streams is stateful, drop down to C is required -// Alternatively we could use stringstream, but its performance is... not good. -std::string getFormattedDuration( double duration ) { -// Max exponent + 1 is required to represent the whole part -// + 1 for decimal point -// + 3 for the 3 decimal places -// + 1 for null terminator -const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; -char buffer[maxDoubleSize]; + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration(double duration) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; -// Save previous errno, to prevent sprintf from overwriting it -ErrnoGuard guard; + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; #ifdef _MSC_VER -sprintf_s(buffer, "%.3f", duration); + sprintf_s(buffer, "%.3f", duration); #else -std::sprintf(buffer, "%.3f", duration); + std::sprintf(buffer, "%.3f", duration); #endif -return std::string(buffer); -} + return std::string(buffer); + } -std::string serializeFilters( std::vector const& container ) { -ReusableStringStream oss; -bool first = true; -for (auto&& filter : container) -{ -if (!first) -oss << ' '; -else -first = false; + std::string serializeFilters(std::vector const& container) { + ReusableStringStream oss; + bool first = true; + for (auto&& filter : container) { + if (!first) + oss << ' '; + else + first = false; -oss << filter; -} -return oss.str(); -} + oss << filter; + } + return oss.str(); + } -TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) -:StreamingReporterBase(_config) {} + TestEventListenerBase::TestEventListenerBase(ReporterConfig const& _config) : StreamingReporterBase(_config) {} -std::set TestEventListenerBase::getSupportedVerbosities() { -return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High }; -} + std::set TestEventListenerBase::getSupportedVerbosities() { + return {Verbosity::Quiet, Verbosity::Normal, Verbosity::High}; + } -void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + void TestEventListenerBase::assertionStarting(AssertionInfo const&) {} -bool TestEventListenerBase::assertionEnded(AssertionStats const &) { -return false; -} + bool TestEventListenerBase::assertionEnded(AssertionStats const&) { return false; } } // end namespace Catch // end catch_reporter_bases.cpp @@ -15489,281 +14729,266 @@ return false; namespace { #ifdef CATCH_PLATFORM_MAC -const char* failedString() { return "FAILED"; } -const char* passedString() { return "PASSED"; } + const char* failedString() { return "FAILED"; } + const char* passedString() { return "PASSED"; } #else -const char* failedString() { return "failed"; } -const char* passedString() { return "passed"; } + const char* failedString() { return "failed"; } + const char* passedString() { return "passed"; } #endif -// Colour::LightGrey -Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } + // Colour::LightGrey + Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } -std::string bothOrAll( std::size_t count ) { -return count == 1 ? std::string() : -count == 2 ? "both " : "all " ; -} + std::string bothOrAll(std::size_t count) { return count == 1 ? std::string() : count == 2 ? "both " : "all "; } } // anon namespace namespace Catch { -namespace { -// Colour, message variants: -// - white: No tests ran. -// - red: Failed [both/all] N test cases, failed [both/all] M assertions. -// - white: Passed [both/all] N test cases (no assertions). -// - red: Failed N tests cases, failed M assertions. -// - green: Passed [both/all] N tests cases with M assertions. -void printTotals(std::ostream& out, const Totals& totals) { -if (totals.testCases.total() == 0) { -out << "No tests ran."; -} else if (totals.testCases.failed == totals.testCases.total()) { -Colour colour(Colour::ResultError); -const std::string qualify_assertions_failed = -totals.assertions.failed == totals.assertions.total() ? -bothOrAll(totals.assertions.failed) : std::string(); -out << -"Failed " << bothOrAll(totals.testCases.failed) -<< pluralise(totals.testCases.failed, "test case") << ", " -"failed " << qualify_assertions_failed << -pluralise(totals.assertions.failed, "assertion") << '.'; -} else if (totals.assertions.total() == 0) { -out << -"Passed " << bothOrAll(totals.testCases.total()) -<< pluralise(totals.testCases.total(), "test case") -<< " (no assertions)."; -} else if (totals.assertions.failed) { -Colour colour(Colour::ResultError); -out << -"Failed " << pluralise(totals.testCases.failed, "test case") << ", " -"failed " << pluralise(totals.assertions.failed, "assertion") << '.'; -} else { -Colour colour(Colour::ResultSuccess); -out << -"Passed " << bothOrAll(totals.testCases.passed) -<< pluralise(totals.testCases.passed, "test case") << -" with " << pluralise(totals.assertions.passed, "assertion") << '.'; -} -} + namespace { + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + void printTotals(std::ostream& out, const Totals& totals) { + if (totals.testCases.total() == 0) { + out << "No tests ran."; + } else if (totals.testCases.failed == totals.testCases.total()) { + Colour colour(Colour::ResultError); + const std::string qualify_assertions_failed = totals.assertions.failed == totals.assertions.total() + ? bothOrAll(totals.assertions.failed) + : std::string(); + out << "Failed " << bothOrAll(totals.testCases.failed) + << pluralise(totals.testCases.failed, "test case") + << ", " + "failed " + << qualify_assertions_failed << pluralise(totals.assertions.failed, "assertion") << '.'; + } else if (totals.assertions.total() == 0) { + out << "Passed " << bothOrAll(totals.testCases.total()) + << pluralise(totals.testCases.total(), "test case") << " (no assertions)."; + } else if (totals.assertions.failed) { + Colour colour(Colour::ResultError); + out << "Failed " << pluralise(totals.testCases.failed, "test case") + << ", " + "failed " + << pluralise(totals.assertions.failed, "assertion") << '.'; + } else { + Colour colour(Colour::ResultSuccess); + out << "Passed " << bothOrAll(totals.testCases.passed) + << pluralise(totals.testCases.passed, "test case") << " with " + << pluralise(totals.assertions.passed, "assertion") << '.'; + } + } -// Implementation of CompactReporter formatting -class AssertionPrinter { -public: -AssertionPrinter& operator= (AssertionPrinter const&) = delete; -AssertionPrinter(AssertionPrinter const&) = delete; -AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) -: stream(_stream) -, result(_stats.assertionResult) -, messages(_stats.infoMessages) -, itMessage(_stats.infoMessages.begin()) -, printInfoMessages(_printInfoMessages) {} + // Implementation of CompactReporter formatting + class AssertionPrinter { + public: + AssertionPrinter& operator=(AssertionPrinter const&) = delete; + AssertionPrinter(AssertionPrinter const&) = delete; + AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream), result(_stats.assertionResult), messages(_stats.infoMessages), + itMessage(_stats.infoMessages.begin()), printInfoMessages(_printInfoMessages) {} -void print() { -printSourceInfo(); + void print() { + printSourceInfo(); -itMessage = messages.begin(); + itMessage = messages.begin(); -switch (result.getResultType()) { -case ResultWas::Ok: -printResultType(Colour::ResultSuccess, passedString()); -printOriginalExpression(); -printReconstructedExpression(); -if (!result.hasExpression()) -printRemainingMessages(Colour::None); -else -printRemainingMessages(); -break; -case ResultWas::ExpressionFailed: -if (result.isOk()) -printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); -else -printResultType(Colour::Error, failedString()); -printOriginalExpression(); -printReconstructedExpression(); -printRemainingMessages(); -break; -case ResultWas::ThrewException: -printResultType(Colour::Error, failedString()); -printIssue("unexpected exception with message:"); -printMessage(); -printExpressionWas(); -printRemainingMessages(); -break; -case ResultWas::FatalErrorCondition: -printResultType(Colour::Error, failedString()); -printIssue("fatal error condition with message:"); -printMessage(); -printExpressionWas(); -printRemainingMessages(); -break; -case ResultWas::DidntThrowException: -printResultType(Colour::Error, failedString()); -printIssue("expected exception, got none"); -printExpressionWas(); -printRemainingMessages(); -break; -case ResultWas::Info: -printResultType(Colour::None, "info"); -printMessage(); -printRemainingMessages(); -break; -case ResultWas::Warning: -printResultType(Colour::None, "warning"); -printMessage(); -printRemainingMessages(); -break; -case ResultWas::ExplicitFailure: -printResultType(Colour::Error, failedString()); -printIssue("explicitly"); -printRemainingMessages(Colour::None); -break; -// These cases are here to prevent compiler warnings -case ResultWas::Unknown: -case ResultWas::FailureBit: -case ResultWas::Exception: -printResultType(Colour::Error, "** internal error **"); -break; -} -} + switch (result.getResultType()) { + case ResultWas::Ok: + printResultType(Colour::ResultSuccess, passedString()); + printOriginalExpression(); + printReconstructedExpression(); + if (!result.hasExpression()) + printRemainingMessages(Colour::None); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) + printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); + else + printResultType(Colour::Error, failedString()); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType(Colour::Error, failedString()); + printIssue("unexpected exception with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType(Colour::Error, failedString()); + printIssue("fatal error condition with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType(Colour::Error, failedString()); + printIssue("expected exception, got none"); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType(Colour::None, "info"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType(Colour::None, "warning"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType(Colour::Error, failedString()); + printIssue("explicitly"); + printRemainingMessages(Colour::None); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: printResultType(Colour::Error, "** internal error **"); break; + } + } -private: -void printSourceInfo() const { -Colour colourGuard(Colour::FileName); -stream << result.getSourceInfo() << ':'; -} + private: + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ':'; + } -void printResultType(Colour::Code colour, std::string const& passOrFail) const { -if (!passOrFail.empty()) { -{ -Colour colourGuard(colour); -stream << ' ' << passOrFail; -} -stream << ':'; -} -} + void printResultType(Colour::Code colour, std::string const& passOrFail) const { + if (!passOrFail.empty()) { + { + Colour colourGuard(colour); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } -void printIssue(std::string const& issue) const { -stream << ' ' << issue; -} + void printIssue(std::string const& issue) const { stream << ' ' << issue; } -void printExpressionWas() { -if (result.hasExpression()) { -stream << ';'; -{ -Colour colour(dimColour()); -stream << " expression was:"; -} -printOriginalExpression(); -} -} + void printExpressionWas() { + if (result.hasExpression()) { + stream << ';'; + { + Colour colour(dimColour()); + stream << " expression was:"; + } + printOriginalExpression(); + } + } -void printOriginalExpression() const { -if (result.hasExpression()) { -stream << ' ' << result.getExpression(); -} -} + void printOriginalExpression() const { + if (result.hasExpression()) { + stream << ' ' << result.getExpression(); + } + } -void printReconstructedExpression() const { -if (result.hasExpandedExpression()) { -{ -Colour colour(dimColour()); -stream << " for: "; -} -stream << result.getExpandedExpression(); -} -} + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + { + Colour colour(dimColour()); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } -void printMessage() { -if (itMessage != messages.end()) { -stream << " '" << itMessage->message << '\''; -++itMessage; -} -} + void printMessage() { + if (itMessage != messages.end()) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } -void printRemainingMessages(Colour::Code colour = dimColour()) { -if (itMessage == messages.end()) -return; + void printRemainingMessages(Colour::Code colour = dimColour()) { + if (itMessage == messages.end()) + return; -const auto itEnd = messages.cend(); -const auto N = static_cast(std::distance(itMessage, itEnd)); + const auto itEnd = messages.cend(); + const auto N = static_cast(std::distance(itMessage, itEnd)); -{ -Colour colourGuard(colour); -stream << " with " << pluralise(N, "message") << ':'; -} + { + Colour colourGuard(colour); + stream << " with " << pluralise(N, "message") << ':'; + } -while (itMessage != itEnd) { -// If this assertion is a warning ignore any INFO messages -if (printInfoMessages || itMessage->type != ResultWas::Info) { -printMessage(); -if (itMessage != itEnd) { -Colour colourGuard(dimColour()); -stream << " and"; -} -continue; -} -++itMessage; -} -} + while (itMessage != itEnd) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || itMessage->type != ResultWas::Info) { + printMessage(); + if (itMessage != itEnd) { + Colour colourGuard(dimColour()); + stream << " and"; + } + continue; + } + ++itMessage; + } + } -private: -std::ostream& stream; -AssertionResult const& result; -std::vector messages; -std::vector::const_iterator itMessage; -bool printInfoMessages; -}; + private: + std::ostream& stream; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; -} // anon namespace + } // anon namespace -std::string CompactReporter::getDescription() { -return "Reports test results on a single line, suitable for IDEs"; -} + std::string CompactReporter::getDescription() { return "Reports test results on a single line, suitable for IDEs"; } -ReporterPreferences CompactReporter::getPreferences() const { -return m_reporterPrefs; -} + ReporterPreferences CompactReporter::getPreferences() const { return m_reporterPrefs; } -void CompactReporter::noMatchingTestCases( std::string const& spec ) { -stream << "No test cases matched '" << spec << '\'' << std::endl; -} + void CompactReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } -void CompactReporter::assertionStarting( AssertionInfo const& ) {} + void CompactReporter::assertionStarting(AssertionInfo const&) {} -bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { -AssertionResult const& result = _assertionStats.assertionResult; + bool CompactReporter::assertionEnded(AssertionStats const& _assertionStats) { + AssertionResult const& result = _assertionStats.assertionResult; -bool printInfoMessages = true; + bool printInfoMessages = true; -// Drop out if result was successful and we're not printing those -if( !m_config->includeSuccessfulResults() && result.isOk() ) { -if( result.getResultType() != ResultWas::Warning ) -return false; -printInfoMessages = false; -} + // Drop out if result was successful and we're not printing those + if (!m_config->includeSuccessfulResults() && result.isOk()) { + if (result.getResultType() != ResultWas::Warning) + return false; + printInfoMessages = false; + } -AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); -printer.print(); + AssertionPrinter printer(stream, _assertionStats, printInfoMessages); + printer.print(); -stream << std::endl; -return true; -} + stream << std::endl; + return true; + } -void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { -if (m_config->showDurations() == ShowDurations::Always) { -stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; -} -} + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name + << std::endl; + } + } -void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { -printTotals( stream, _testRunStats.totals ); -stream << '\n' << std::endl; -StreamingReporterBase::testRunEnded( _testRunStats ); -} + void CompactReporter::testRunEnded(TestRunStats const& _testRunStats) { + printTotals(stream, _testRunStats.totals); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded(_testRunStats); + } -CompactReporter::~CompactReporter() {} + CompactReporter::~CompactReporter() {} -CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + CATCH_REGISTER_REPORTER("compact", CompactReporter) } // end namespace Catch // end catch_reporter_compact.cpp @@ -15774,673 +14999,614 @@ CATCH_REGISTER_REPORTER( "compact", CompactReporter ) #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch +#pragma warning(disable : 4061) // Not all labels are EXPLICITLY handled in switch // Note that 4062 (not all labels are handled and default is missing) is enabled #endif #if defined(__clang__) -# pragma clang diagnostic push +#pragma clang diagnostic push // For simplicity, benchmarking-only helpers are always enabled -# pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wunused-function" #endif namespace Catch { -namespace { + namespace { -// Formatter impl for ConsoleReporter -class ConsoleAssertionPrinter { -public: -ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; -ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; -ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) -: stream(_stream), -stats(_stats), -result(_stats.assertionResult), -colour(Colour::None), -message(result.getMessage()), -messages(_stats.infoMessages), -printInfoMessages(_printInfoMessages) { -switch (result.getResultType()) { -case ResultWas::Ok: -colour = Colour::Success; -passOrFail = "PASSED"; -//if( result.hasMessage() ) -if (_stats.infoMessages.size() == 1) -messageLabel = "with message"; -if (_stats.infoMessages.size() > 1) -messageLabel = "with messages"; -break; -case ResultWas::ExpressionFailed: -if (result.isOk()) { -colour = Colour::Success; -passOrFail = "FAILED - but was ok"; -} else { -colour = Colour::Error; -passOrFail = "FAILED"; -} -if (_stats.infoMessages.size() == 1) -messageLabel = "with message"; -if (_stats.infoMessages.size() > 1) -messageLabel = "with messages"; -break; -case ResultWas::ThrewException: -colour = Colour::Error; -passOrFail = "FAILED"; -messageLabel = "due to unexpected exception with "; -if (_stats.infoMessages.size() == 1) -messageLabel += "message"; -if (_stats.infoMessages.size() > 1) -messageLabel += "messages"; -break; -case ResultWas::FatalErrorCondition: -colour = Colour::Error; -passOrFail = "FAILED"; -messageLabel = "due to a fatal error condition"; -break; -case ResultWas::DidntThrowException: -colour = Colour::Error; -passOrFail = "FAILED"; -messageLabel = "because no exception was thrown where one was expected"; -break; -case ResultWas::Info: -messageLabel = "info"; -break; -case ResultWas::Warning: -messageLabel = "warning"; -break; -case ResultWas::ExplicitFailure: -passOrFail = "FAILED"; -colour = Colour::Error; -if (_stats.infoMessages.size() == 1) -messageLabel = "explicitly with message"; -if (_stats.infoMessages.size() > 1) -messageLabel = "explicitly with messages"; -break; -// These cases are here to prevent compiler warnings -case ResultWas::Unknown: -case ResultWas::FailureBit: -case ResultWas::Exception: -passOrFail = "** internal error **"; -colour = Colour::Error; -break; -} -} + // Formatter impl for ConsoleReporter + class ConsoleAssertionPrinter { + public: + ConsoleAssertionPrinter& operator=(ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream), stats(_stats), result(_stats.assertionResult), colour(Colour::None), + message(result.getMessage()), messages(_stats.infoMessages), printInfoMessages(_printInfoMessages) { + switch (result.getResultType()) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + // if( result.hasMessage() ) + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with "; + if (_stats.infoMessages.size() == 1) + messageLabel += "message"; + if (_stats.infoMessages.size() > 1) + messageLabel += "messages"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: messageLabel = "info"; break; + case ResultWas::Warning: messageLabel = "warning"; break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if (_stats.infoMessages.size() == 1) + messageLabel = "explicitly with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } -void print() const { -printSourceInfo(); -if (stats.totals.assertions.total() > 0) { -printResultType(); -printOriginalExpression(); -printReconstructedExpression(); -} else { -stream << '\n'; -} -printMessage(); -} + void print() const { + printSourceInfo(); + if (stats.totals.assertions.total() > 0) { + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } else { + stream << '\n'; + } + printMessage(); + } -private: -void printResultType() const { -if (!passOrFail.empty()) { -Colour colourGuard(colour); -stream << passOrFail << ":\n"; -} -} -void printOriginalExpression() const { -if (result.hasExpression()) { -Colour colourGuard(Colour::OriginalExpression); -stream << " "; -stream << result.getExpressionInMacro(); -stream << '\n'; -} -} -void printReconstructedExpression() const { -if (result.hasExpandedExpression()) { -stream << "with expansion:\n"; -Colour colourGuard(Colour::ReconstructedExpression); -stream << Column(result.getExpandedExpression()).indent(2) << '\n'; -} -} -void printMessage() const { -if (!messageLabel.empty()) -stream << messageLabel << ':' << '\n'; -for (auto const& msg : messages) { -// If this assertion is a warning ignore any INFO messages -if (printInfoMessages || msg.type != ResultWas::Info) -stream << Column(msg.message).indent(2) << '\n'; -} -} -void printSourceInfo() const { -Colour colourGuard(Colour::FileName); -stream << result.getSourceInfo() << ": "; -} + private: + void printResultType() const { + if (!passOrFail.empty()) { + Colour colourGuard(colour); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if (result.hasExpression()) { + Colour colourGuard(Colour::OriginalExpression); + stream << " "; + stream << result.getExpressionInMacro(); + stream << '\n'; + } + } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + stream << "with expansion:\n"; + Colour colourGuard(Colour::ReconstructedExpression); + stream << Column(result.getExpandedExpression()).indent(2) << '\n'; + } + } + void printMessage() const { + if (!messageLabel.empty()) + stream << messageLabel << ':' << '\n'; + for (auto const& msg : messages) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || msg.type != ResultWas::Info) + stream << Column(msg.message).indent(2) << '\n'; + } + } + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ": "; + } -std::ostream& stream; -AssertionStats const& stats; -AssertionResult const& result; -Colour::Code colour; -std::string passOrFail; -std::string messageLabel; -std::string message; -std::vector messages; -bool printInfoMessages; -}; + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; -std::size_t makeRatio(std::size_t number, std::size_t total) { -std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; -return (ratio == 0 && number > 0) ? 1 : ratio; -} + std::size_t makeRatio(std::size_t number, std::size_t total) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; + return (ratio == 0 && number > 0) ? 1 : ratio; + } -std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { -if (i > j && i > k) -return i; -else if (j > k) -return j; -else -return k; -} + std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { + if (i > j && i > k) + return i; + else if (j > k) + return j; + else + return k; + } -struct ColumnInfo { -enum Justification { Left, Right }; -std::string name; -int width; -Justification justification; -}; -struct ColumnBreak {}; -struct RowBreak {}; + struct ColumnInfo { + enum Justification { Left, Right }; + std::string name; + int width; + Justification justification; + }; + struct ColumnBreak {}; + struct RowBreak {}; -class Duration { -enum class Unit { -Auto, -Nanoseconds, -Microseconds, -Milliseconds, -Seconds, -Minutes -}; -static const uint64_t s_nanosecondsInAMicrosecond = 1000; -static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; -static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; -static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; + class Duration { + enum class Unit { Auto, Nanoseconds, Microseconds, Milliseconds, Seconds, Minutes }; + static const uint64_t s_nanosecondsInAMicrosecond = 1000; + static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; + static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; -uint64_t m_inNanoseconds; -Unit m_units; + uint64_t m_inNanoseconds; + Unit m_units; -public: -explicit Duration(double inNanoseconds, Unit units = Unit::Auto) -: Duration(static_cast(inNanoseconds), units) { -} + public: + explicit Duration(double inNanoseconds, Unit units = Unit::Auto) + : Duration(static_cast(inNanoseconds), units) {} -explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) -: m_inNanoseconds(inNanoseconds), -m_units(units) { -if (m_units == Unit::Auto) { -if (m_inNanoseconds < s_nanosecondsInAMicrosecond) -m_units = Unit::Nanoseconds; -else if (m_inNanoseconds < s_nanosecondsInAMillisecond) -m_units = Unit::Microseconds; -else if (m_inNanoseconds < s_nanosecondsInASecond) -m_units = Unit::Milliseconds; -else if (m_inNanoseconds < s_nanosecondsInAMinute) -m_units = Unit::Seconds; -else -m_units = Unit::Minutes; -} + explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + : m_inNanoseconds(inNanoseconds), m_units(units) { + if (m_units == Unit::Auto) { + if (m_inNanoseconds < s_nanosecondsInAMicrosecond) + m_units = Unit::Nanoseconds; + else if (m_inNanoseconds < s_nanosecondsInAMillisecond) + m_units = Unit::Microseconds; + else if (m_inNanoseconds < s_nanosecondsInASecond) + m_units = Unit::Milliseconds; + else if (m_inNanoseconds < s_nanosecondsInAMinute) + m_units = Unit::Seconds; + else + m_units = Unit::Minutes; + } + } -} + auto value() const -> double { + switch (m_units) { + case Unit::Microseconds: return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); + case Unit::Milliseconds: return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); + case Unit::Seconds: return m_inNanoseconds / static_cast(s_nanosecondsInASecond); + case Unit::Minutes: return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); + default: return static_cast(m_inNanoseconds); + } + } + auto unitsAsString() const -> std::string { + switch (m_units) { + case Unit::Nanoseconds: return "ns"; + case Unit::Microseconds: return "us"; + case Unit::Milliseconds: return "ms"; + case Unit::Seconds: return "s"; + case Unit::Minutes: return "m"; + default: return "** internal error **"; + } + } + friend auto operator<<(std::ostream& os, Duration const& duration) -> std::ostream& { + return os << duration.value() << ' ' << duration.unitsAsString(); + } + }; + } // end anon namespace -auto value() const -> double { -switch (m_units) { -case Unit::Microseconds: -return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); -case Unit::Milliseconds: -return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); -case Unit::Seconds: -return m_inNanoseconds / static_cast(s_nanosecondsInASecond); -case Unit::Minutes: -return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); -default: -return static_cast(m_inNanoseconds); -} -} -auto unitsAsString() const -> std::string { -switch (m_units) { -case Unit::Nanoseconds: -return "ns"; -case Unit::Microseconds: -return "us"; -case Unit::Milliseconds: -return "ms"; -case Unit::Seconds: -return "s"; -case Unit::Minutes: -return "m"; -default: -return "** internal error **"; -} + class TablePrinter { + std::ostream& m_os; + std::vector m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; -} -friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { -return os << duration.value() << ' ' << duration.unitsAsString(); -} -}; -} // end anon namespace + public: + TablePrinter(std::ostream& os, std::vector columnInfos) + : m_os(os), m_columnInfos(std::move(columnInfos)) {} -class TablePrinter { -std::ostream& m_os; -std::vector m_columnInfos; -std::ostringstream m_oss; -int m_currentColumn = -1; -bool m_isOpen = false; + auto columnInfos() const -> std::vector const& { return m_columnInfos; } -public: -TablePrinter( std::ostream& os, std::vector columnInfos ) -: m_os( os ), -m_columnInfos( std::move( columnInfos ) ) {} + void open() { + if (!m_isOpen) { + m_isOpen = true; + *this << RowBreak(); -auto columnInfos() const -> std::vector const& { -return m_columnInfos; -} + Columns headerCols; + Spacer spacer(2); + for (auto const& info : m_columnInfos) { + headerCols += Column(info.name).width(static_cast(info.width - 2)); + headerCols += spacer; + } + m_os << headerCols << '\n'; -void open() { -if (!m_isOpen) { -m_isOpen = true; -*this << RowBreak(); + m_os << Catch::getLineOfChars<'-'>() << '\n'; + } + } + void close() { + if (m_isOpen) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; + } + } -Columns headerCols; -Spacer spacer(2); -for (auto const& info : m_columnInfos) { -headerCols += Column(info.name).width(static_cast(info.width - 2)); -headerCols += spacer; -} -m_os << headerCols << '\n'; + template friend TablePrinter& operator<<(TablePrinter& tp, T const& value) { + tp.m_oss << value; + return tp; + } -m_os << Catch::getLineOfChars<'-'>() << '\n'; -} -} -void close() { -if (m_isOpen) { -*this << RowBreak(); -m_os << std::endl; -m_isOpen = false; -} -} + friend TablePrinter& operator<<(TablePrinter& tp, ColumnBreak) { + auto colStr = tp.m_oss.str(); + const auto strSize = colStr.size(); + tp.m_oss.str(""); + tp.open(); + if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { + tp.m_currentColumn = -1; + tp.m_os << '\n'; + } + tp.m_currentColumn++; -template -friend TablePrinter& operator << (TablePrinter& tp, T const& value) { -tp.m_oss << value; -return tp; -} + auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; + auto padding = (strSize + 1 < static_cast(colInfo.width)) + ? std::string(colInfo.width - (strSize + 1), ' ') + : std::string(); + if (colInfo.justification == ColumnInfo::Left) + tp.m_os << colStr << padding << ' '; + else + tp.m_os << padding << colStr << ' '; + return tp; + } -friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { -auto colStr = tp.m_oss.str(); -const auto strSize = colStr.size(); -tp.m_oss.str(""); -tp.open(); -if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { -tp.m_currentColumn = -1; -tp.m_os << '\n'; -} -tp.m_currentColumn++; + friend TablePrinter& operator<<(TablePrinter& tp, RowBreak) { + if (tp.m_currentColumn > 0) { + tp.m_os << '\n'; + tp.m_currentColumn = -1; + } + return tp; + } + }; -auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; -auto padding = (strSize + 1 < static_cast(colInfo.width)) -? std::string(colInfo.width - (strSize + 1), ' ') -: std::string(); -if (colInfo.justification == ColumnInfo::Left) -tp.m_os << colStr << padding << ' '; -else -tp.m_os << padding << colStr << ' '; -return tp; -} + ConsoleReporter::ConsoleReporter(ReporterConfig const& config) + : StreamingReporterBase(config), + m_tablePrinter(new TablePrinter(config.stream(), [&config]() -> std::vector { + if (config.fullConfig()->benchmarkNoAnalysis()) { + return {{"benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left}, + {" samples", 14, ColumnInfo::Right}, + {" iterations", 14, ColumnInfo::Right}, + {" mean", 14, ColumnInfo::Right}}; + } else { + return {{"benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left}, + {"samples mean std dev", 14, ColumnInfo::Right}, + {"iterations low mean low std dev", 14, ColumnInfo::Right}, + {"estimated high mean high std dev", 14, ColumnInfo::Right}}; + } + }())) {} + ConsoleReporter::~ConsoleReporter() = default; -friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { -if (tp.m_currentColumn > 0) { -tp.m_os << '\n'; -tp.m_currentColumn = -1; -} -return tp; -} -}; + std::string ConsoleReporter::getDescription() { return "Reports test results as plain lines of text"; } -ConsoleReporter::ConsoleReporter(ReporterConfig const& config) -: StreamingReporterBase(config), -m_tablePrinter(new TablePrinter(config.stream(), -[&config]() -> std::vector { -if (config.fullConfig()->benchmarkNoAnalysis()) -{ -return{ -{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, -{ " samples", 14, ColumnInfo::Right }, -{ " iterations", 14, ColumnInfo::Right }, -{ " mean", 14, ColumnInfo::Right } -}; -} -else -{ -return{ -{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, -{ "samples mean std dev", 14, ColumnInfo::Right }, -{ "iterations low mean low std dev", 14, ColumnInfo::Right }, -{ "estimated high mean high std dev", 14, ColumnInfo::Right } -}; -} -}())) {} -ConsoleReporter::~ConsoleReporter() = default; + void ConsoleReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } -std::string ConsoleReporter::getDescription() { -return "Reports test results as plain lines of text"; -} + void ConsoleReporter::reportInvalidArguments(std::string const& arg) { + stream << "Invalid Filter: " << arg << std::endl; + } -void ConsoleReporter::noMatchingTestCases(std::string const& spec) { -stream << "No test cases matched '" << spec << '\'' << std::endl; -} + void ConsoleReporter::assertionStarting(AssertionInfo const&) {} -void ConsoleReporter::reportInvalidArguments(std::string const&arg){ -stream << "Invalid Filter: " << arg << std::endl; -} + bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { + AssertionResult const& result = _assertionStats.assertionResult; -void ConsoleReporter::assertionStarting(AssertionInfo const&) {} + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); -bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { -AssertionResult const& result = _assertionStats.assertionResult; + // Drop out if result was successful but we're not printing them. + if (!includeResults && result.getResultType() != ResultWas::Warning) + return false; -bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + lazyPrint(); -// Drop out if result was successful but we're not printing them. -if (!includeResults && result.getResultType() != ResultWas::Warning) -return false; + ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); + printer.print(); + stream << std::endl; + return true; + } -lazyPrint(); - -ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); -printer.print(); -stream << std::endl; -return true; -} - -void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { -m_tablePrinter->close(); -m_headerPrinted = false; -StreamingReporterBase::sectionStarting(_sectionInfo); -} -void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { -m_tablePrinter->close(); -if (_sectionStats.missingAssertions) { -lazyPrint(); -Colour colour(Colour::ResultError); -if (m_sectionStack.size() > 1) -stream << "\nNo assertions in section"; -else -stream << "\nNo assertions in test case"; -stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; -} -if (m_config->showDurations() == ShowDurations::Always) { -stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; -} -if (m_headerPrinted) { -m_headerPrinted = false; -} -StreamingReporterBase::sectionEnded(_sectionStats); -} + void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + m_tablePrinter->close(); + m_headerPrinted = false; + StreamingReporterBase::sectionStarting(_sectionInfo); + } + void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { + m_tablePrinter->close(); + if (_sectionStats.missingAssertions) { + lazyPrint(); + Colour colour(Colour::ResultError); + if (m_sectionStack.size() > 1) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name + << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; + } + StreamingReporterBase::sectionEnded(_sectionStats); + } #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -void ConsoleReporter::benchmarkPreparing(std::string const& name) { -lazyPrintWithoutClosingBenchmarkTable(); + void ConsoleReporter::benchmarkPreparing(std::string const& name) { + lazyPrintWithoutClosingBenchmarkTable(); -auto nameCol = Column(name).width(static_cast(m_tablePrinter->columnInfos()[0].width - 2)); + auto nameCol = Column(name).width(static_cast(m_tablePrinter->columnInfos()[0].width - 2)); -bool firstLine = true; -for (auto line : nameCol) { -if (!firstLine) -(*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); -else -firstLine = false; + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; -(*m_tablePrinter) << line << ColumnBreak(); -} -} + (*m_tablePrinter) << line << ColumnBreak(); + } + } -void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { -(*m_tablePrinter) << info.samples << ColumnBreak() -<< info.iterations << ColumnBreak(); -if (!m_config->benchmarkNoAnalysis()) -(*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); -} -void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { -if (m_config->benchmarkNoAnalysis()) -{ -(*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak(); -} -else -{ -(*m_tablePrinter) << ColumnBreak() -<< Duration(stats.mean.point.count()) << ColumnBreak() -<< Duration(stats.mean.lower_bound.count()) << ColumnBreak() -<< Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak() -<< Duration(stats.standardDeviation.point.count()) << ColumnBreak() -<< Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak() -<< Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak(); -} -} + void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + (*m_tablePrinter) << info.samples << ColumnBreak() << info.iterations << ColumnBreak(); + if (!m_config->benchmarkNoAnalysis()) + (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); + } + void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { + if (m_config->benchmarkNoAnalysis()) { + (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak(); + } else { + (*m_tablePrinter) << ColumnBreak() << Duration(stats.mean.point.count()) << ColumnBreak() + << Duration(stats.mean.lower_bound.count()) << ColumnBreak() + << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak() + << Duration(stats.standardDeviation.point.count()) << ColumnBreak() + << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak() + << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() + << ColumnBreak() << ColumnBreak() << ColumnBreak(); + } + } -void ConsoleReporter::benchmarkFailed(std::string const& error) { -Colour colour(Colour::Red); -(*m_tablePrinter) -<< "Benchmark failed (" << error << ')' -<< ColumnBreak() << RowBreak(); -} + void ConsoleReporter::benchmarkFailed(std::string const& error) { + Colour colour(Colour::Red); + (*m_tablePrinter) << "Benchmark failed (" << error << ')' << ColumnBreak() << RowBreak(); + } #endif // CATCH_CONFIG_ENABLE_BENCHMARKING -void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { -m_tablePrinter->close(); -StreamingReporterBase::testCaseEnded(_testCaseStats); -m_headerPrinted = false; -} -void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { -if (currentGroupInfo.used) { -printSummaryDivider(); -stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; -printTotals(_testGroupStats.totals); -stream << '\n' << std::endl; -} -StreamingReporterBase::testGroupEnded(_testGroupStats); -} -void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { -printTotalsDivider(_testRunStats.totals); -printTotals(_testRunStats.totals); -stream << std::endl; -StreamingReporterBase::testRunEnded(_testRunStats); -} -void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { -StreamingReporterBase::testRunStarting(_testInfo); -printTestFilters(); -} + void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { + m_tablePrinter->close(); + StreamingReporterBase::testCaseEnded(_testCaseStats); + m_headerPrinted = false; + } + void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { + if (currentGroupInfo.used) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals(_testGroupStats.totals); + stream << '\n' << std::endl; + } + StreamingReporterBase::testGroupEnded(_testGroupStats); + } + void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { + printTotalsDivider(_testRunStats.totals); + printTotals(_testRunStats.totals); + stream << std::endl; + StreamingReporterBase::testRunEnded(_testRunStats); + } + void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { + StreamingReporterBase::testRunStarting(_testInfo); + printTestFilters(); + } -void ConsoleReporter::lazyPrint() { + void ConsoleReporter::lazyPrint() { -m_tablePrinter->close(); -lazyPrintWithoutClosingBenchmarkTable(); -} + m_tablePrinter->close(); + lazyPrintWithoutClosingBenchmarkTable(); + } -void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { + void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { -if (!currentTestRunInfo.used) -lazyPrintRunInfo(); -if (!currentGroupInfo.used) -lazyPrintGroupInfo(); + if (!currentTestRunInfo.used) + lazyPrintRunInfo(); + if (!currentGroupInfo.used) + lazyPrintGroupInfo(); -if (!m_headerPrinted) { -printTestCaseAndSectionHeader(); -m_headerPrinted = true; -} -} -void ConsoleReporter::lazyPrintRunInfo() { -stream << '\n' << getLineOfChars<'~'>() << '\n'; -Colour colour(Colour::SecondaryText); -stream << currentTestRunInfo->name -<< " is a Catch v" << libraryVersion() << " host application.\n" -<< "Run with -? for options\n\n"; + if (!m_headerPrinted) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void ConsoleReporter::lazyPrintRunInfo() { + stream << '\n' << getLineOfChars<'~'>() << '\n'; + Colour colour(Colour::SecondaryText); + stream << currentTestRunInfo->name << " is a Catch v" << libraryVersion() << " host application.\n" + << "Try with -? for options\n\n"; -if (m_config->rngSeed() != 0) -stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + if (m_config->rngSeed() != 0) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; -currentTestRunInfo.used = true; -} -void ConsoleReporter::lazyPrintGroupInfo() { -if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { -printClosedHeader("Group: " + currentGroupInfo->name); -currentGroupInfo.used = true; -} -} -void ConsoleReporter::printTestCaseAndSectionHeader() { -assert(!m_sectionStack.empty()); -printOpenHeader(currentTestCaseInfo->name); + currentTestRunInfo.used = true; + } + void ConsoleReporter::lazyPrintGroupInfo() { + if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { + printClosedHeader("Group: " + currentGroupInfo->name); + currentGroupInfo.used = true; + } + } + void ConsoleReporter::printTestCaseAndSectionHeader() { + assert(!m_sectionStack.empty()); + printOpenHeader(currentTestCaseInfo->name); -if (m_sectionStack.size() > 1) { -Colour colourGuard(Colour::Headers); + if (m_sectionStack.size() > 1) { + Colour colourGuard(Colour::Headers); -auto -it = m_sectionStack.begin() + 1, // Skip first section (test case) -itEnd = m_sectionStack.end(); -for (; it != itEnd; ++it) -printHeaderString(it->name, 2); -} + auto it = m_sectionStack.begin() + 1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for (; it != itEnd; ++it) + printHeaderString(it->name, 2); + } -SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; -stream << getLineOfChars<'-'>() << '\n'; -Colour colourGuard(Colour::FileName); -stream << lineInfo << '\n'; -stream << getLineOfChars<'.'>() << '\n' << std::endl; -} + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; + stream << getLineOfChars<'.'>() << '\n' << std::endl; + } -void ConsoleReporter::printClosedHeader(std::string const& _name) { -printOpenHeader(_name); -stream << getLineOfChars<'.'>() << '\n'; -} -void ConsoleReporter::printOpenHeader(std::string const& _name) { -stream << getLineOfChars<'-'>() << '\n'; -{ -Colour colourGuard(Colour::Headers); -printHeaderString(_name); -} -} + void ConsoleReporter::printClosedHeader(std::string const& _name) { + printOpenHeader(_name); + stream << getLineOfChars<'.'>() << '\n'; + } + void ConsoleReporter::printOpenHeader(std::string const& _name) { + stream << getLineOfChars<'-'>() << '\n'; + { + Colour colourGuard(Colour::Headers); + printHeaderString(_name); + } + } -// if string has a : in first line will set indent to follow it on -// subsequent lines -void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { -std::size_t i = _string.find(": "); -if (i != std::string::npos) -i += 2; -else -i = 0; -stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; -} + // if string has a : in first line will set indent to follow it on + // subsequent lines + void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { + std::size_t i = _string.find(": "); + if (i != std::string::npos) + i += 2; + else + i = 0; + stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; + } -struct SummaryColumn { + struct SummaryColumn { -SummaryColumn( std::string _label, Colour::Code _colour ) -: label( std::move( _label ) ), -colour( _colour ) {} -SummaryColumn addRow( std::size_t count ) { -ReusableStringStream rss; -rss << count; -std::string row = rss.str(); -for (auto& oldRow : rows) { -while (oldRow.size() < row.size()) -oldRow = ' ' + oldRow; -while (oldRow.size() > row.size()) -row = ' ' + row; -} -rows.push_back(row); -return *this; -} + SummaryColumn(std::string _label, Colour::Code _colour) : label(std::move(_label)), colour(_colour) {} + SummaryColumn addRow(std::size_t count) { + ReusableStringStream rss; + rss << count; + std::string row = rss.str(); + for (auto& oldRow : rows) { + while (oldRow.size() < row.size()) + oldRow = ' ' + oldRow; + while (oldRow.size() > row.size()) + row = ' ' + row; + } + rows.push_back(row); + return *this; + } -std::string label; -Colour::Code colour; -std::vector rows; + std::string label; + Colour::Code colour; + std::vector rows; + }; -}; + void ConsoleReporter::printTotals(Totals const& totals) { + if (totals.testCases.total() == 0) { + stream << Colour(Colour::Warning) << "No tests ran\n"; + } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { + stream << Colour(Colour::ResultSuccess) << "All tests passed"; + stream << " (" << pluralise(totals.assertions.passed, "assertion") << " in " + << pluralise(totals.testCases.passed, "test case") << ')' << '\n'; + } else { -void ConsoleReporter::printTotals( Totals const& totals ) { -if (totals.testCases.total() == 0) { -stream << Colour(Colour::Warning) << "No tests ran\n"; -} else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { -stream << Colour(Colour::ResultSuccess) << "All tests passed"; -stream << " (" -<< pluralise(totals.assertions.passed, "assertion") << " in " -<< pluralise(totals.testCases.passed, "test case") << ')' -<< '\n'; -} else { + std::vector columns; + columns.push_back( + SummaryColumn("", Colour::None).addRow(totals.testCases.total()).addRow(totals.assertions.total())); + columns.push_back(SummaryColumn("passed", Colour::Success) + .addRow(totals.testCases.passed) + .addRow(totals.assertions.passed)); + columns.push_back(SummaryColumn("failed", Colour::ResultError) + .addRow(totals.testCases.failed) + .addRow(totals.assertions.failed)); + columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) + .addRow(totals.testCases.failedButOk) + .addRow(totals.assertions.failedButOk)); -std::vector columns; -columns.push_back(SummaryColumn("", Colour::None) -.addRow(totals.testCases.total()) -.addRow(totals.assertions.total())); -columns.push_back(SummaryColumn("passed", Colour::Success) -.addRow(totals.testCases.passed) -.addRow(totals.assertions.passed)); -columns.push_back(SummaryColumn("failed", Colour::ResultError) -.addRow(totals.testCases.failed) -.addRow(totals.assertions.failed)); -columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) -.addRow(totals.testCases.failedButOk) -.addRow(totals.assertions.failedButOk)); + printSummaryRow("test cases", columns, 0); + printSummaryRow("assertions", columns, 1); + } + } + void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, + std::size_t row) { + for (auto col : cols) { + std::string value = col.rows[row]; + if (col.label.empty()) { + stream << label << ": "; + if (value != "0") + stream << value; + else + stream << Colour(Colour::Warning) << "- none -"; + } else if (value != "0") { + stream << Colour(Colour::LightGrey) << " | "; + stream << Colour(col.colour) << value << ' ' << col.label; + } + } + stream << '\n'; + } -printSummaryRow("test cases", columns, 0); -printSummaryRow("assertions", columns, 1); -} -} -void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { -for (auto col : cols) { -std::string value = col.rows[row]; -if (col.label.empty()) { -stream << label << ": "; -if (value != "0") -stream << value; -else -stream << Colour(Colour::Warning) << "- none -"; -} else if (value != "0") { -stream << Colour(Colour::LightGrey) << " | "; -stream << Colour(col.colour) -<< value << ' ' << col.label; -} -} -stream << '\n'; -} + void ConsoleReporter::printTotalsDivider(Totals const& totals) { + if (totals.testCases.total() > 0) { + std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); + std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); + std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)++; + while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)--; -void ConsoleReporter::printTotalsDivider(Totals const& totals) { -if (totals.testCases.total() > 0) { -std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); -std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); -std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); -while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) -findMax(failedRatio, failedButOkRatio, passedRatio)++; -while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) -findMax(failedRatio, failedButOkRatio, passedRatio)--; + stream << Colour(Colour::Error) << std::string(failedRatio, '='); + stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); + if (totals.testCases.allPassed()) + stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); + else + stream << Colour(Colour::Success) << std::string(passedRatio, '='); + } else { + stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); + } + stream << '\n'; + } + void ConsoleReporter::printSummaryDivider() { stream << getLineOfChars<'-'>() << '\n'; } -stream << Colour(Colour::Error) << std::string(failedRatio, '='); -stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); -if (totals.testCases.allPassed()) -stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); -else -stream << Colour(Colour::Success) << std::string(passedRatio, '='); -} else { -stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); -} -stream << '\n'; -} -void ConsoleReporter::printSummaryDivider() { -stream << getLineOfChars<'-'>() << '\n'; -} + void ConsoleReporter::printTestFilters() { + if (m_config->testSpec().hasFilters()) + stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters(m_config->getTestsOrTags()) + << '\n'; + } -void ConsoleReporter::printTestFilters() { -if (m_config->testSpec().hasFilters()) -stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n'; -} - -CATCH_REGISTER_REPORTER("console", ConsoleReporter) + CATCH_REGISTER_REPORTER("console", ConsoleReporter) } // end namespace Catch @@ -16449,273 +15615,252 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter) #endif #if defined(__clang__) -# pragma clang diagnostic pop +#pragma clang diagnostic pop #endif // end catch_reporter_console.cpp // start catch_reporter_junit.cpp -#include -#include -#include #include +#include +#include +#include namespace Catch { -namespace { -std::string getCurrentTimestamp() { -// Beware, this is not reentrant because of backward compatibility issues -// Also, UTC only, again because of backward compatibility (%z is C++11) -time_t rawtime; -std::time(&rawtime); -auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + namespace { + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); #ifdef _MSC_VER -std::tm timeInfo = {}; -gmtime_s(&timeInfo, &rawtime); + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); #else -std::tm* timeInfo; -timeInfo = std::gmtime(&rawtime); + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); #endif -char timeStamp[timeStampSize]; -const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + char timeStamp[timeStampSize]; + const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER -std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else -std::strftime(timeStamp, timeStampSize, fmt, timeInfo); + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif -return std::string(timeStamp); -} + return std::string(timeStamp); + } -std::string fileNameTag(const std::vector &tags) { -auto it = std::find_if(begin(tags), -end(tags), -[] (std::string const& tag) {return tag.front() == '#'; }); -if (it != tags.end()) -return it->substr(1); -return std::string(); -} -} // anonymous namespace + std::string fileNameTag(const std::vector& tags) { + auto it = std::find_if(begin(tags), end(tags), [](std::string const& tag) { return tag.front() == '#'; }); + if (it != tags.end()) + return it->substr(1); + return std::string(); + } + } // anonymous namespace -JunitReporter::JunitReporter( ReporterConfig const& _config ) -: CumulativeReporterBase( _config ), -xml( _config.stream() ) -{ -m_reporterPrefs.shouldRedirectStdOut = true; -m_reporterPrefs.shouldReportAllAssertions = true; -} + JunitReporter::JunitReporter(ReporterConfig const& _config) + : CumulativeReporterBase(_config), xml(_config.stream()) { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } -JunitReporter::~JunitReporter() {} + JunitReporter::~JunitReporter() {} -std::string JunitReporter::getDescription() { -return "Reports test results in an XML format that looks like Ant's junitreport target"; -} + std::string JunitReporter::getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } -void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} + void JunitReporter::noMatchingTestCases(std::string const& /*spec*/) {} -void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { -CumulativeReporterBase::testRunStarting( runInfo ); -xml.startElement( "testsuites" ); -} + void JunitReporter::testRunStarting(TestRunInfo const& runInfo) { + CumulativeReporterBase::testRunStarting(runInfo); + xml.startElement("testsuites"); + } -void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { -suiteTimer.start(); -stdOutForSuite.clear(); -stdErrForSuite.clear(); -unexpectedExceptions = 0; -CumulativeReporterBase::testGroupStarting( groupInfo ); -} + void JunitReporter::testGroupStarting(GroupInfo const& groupInfo) { + suiteTimer.start(); + stdOutForSuite.clear(); + stdErrForSuite.clear(); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting(groupInfo); + } -void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { -m_okToFail = testCaseInfo.okToFail(); -} + void JunitReporter::testCaseStarting(TestCaseInfo const& testCaseInfo) { m_okToFail = testCaseInfo.okToFail(); } -bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { -if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) -unexpectedExceptions++; -return CumulativeReporterBase::assertionEnded( assertionStats ); -} + bool JunitReporter::assertionEnded(AssertionStats const& assertionStats) { + if (assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded(assertionStats); + } -void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { -stdOutForSuite += testCaseStats.stdOut; -stdErrForSuite += testCaseStats.stdErr; -CumulativeReporterBase::testCaseEnded( testCaseStats ); -} + void JunitReporter::testCaseEnded(TestCaseStats const& testCaseStats) { + stdOutForSuite += testCaseStats.stdOut; + stdErrForSuite += testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded(testCaseStats); + } -void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { -double suiteTime = suiteTimer.getElapsedSeconds(); -CumulativeReporterBase::testGroupEnded( testGroupStats ); -writeGroup( *m_testGroups.back(), suiteTime ); -} + void JunitReporter::testGroupEnded(TestGroupStats const& testGroupStats) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded(testGroupStats); + writeGroup(*m_testGroups.back(), suiteTime); + } -void JunitReporter::testRunEndedCumulative() { -xml.endElement(); -} + void JunitReporter::testRunEndedCumulative() { xml.endElement(); } -void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { -XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + void JunitReporter::writeGroup(TestGroupNode const& groupNode, double suiteTime) { + XmlWriter::ScopedElement e = xml.scopedElement("testsuite"); -TestGroupStats const& stats = groupNode.value; -xml.writeAttribute( "name", stats.groupInfo.name ); -xml.writeAttribute( "errors", unexpectedExceptions ); -xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); -xml.writeAttribute( "tests", stats.totals.assertions.total() ); -xml.writeAttribute( "hostname", "tbd" ); // !TBD -if( m_config->showDurations() == ShowDurations::Never ) -xml.writeAttribute( "time", "" ); -else -xml.writeAttribute( "time", suiteTime ); -xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute("name", stats.groupInfo.name); + xml.writeAttribute("errors", unexpectedExceptions); + xml.writeAttribute("failures", stats.totals.assertions.failed - unexpectedExceptions); + xml.writeAttribute("tests", stats.totals.assertions.total()); + xml.writeAttribute("hostname", "tbd"); // !TBD + if (m_config->showDurations() == ShowDurations::Never) + xml.writeAttribute("time", ""); + else + xml.writeAttribute("time", suiteTime); + xml.writeAttribute("timestamp", getCurrentTimestamp()); -// Write properties if there are any -if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { -auto properties = xml.scopedElement("properties"); -if (m_config->hasTestFilters()) { -xml.scopedElement("property") -.writeAttribute("name", "filters") -.writeAttribute("value", serializeFilters(m_config->getTestsOrTags())); -} -if (m_config->rngSeed() != 0) { -xml.scopedElement("property") -.writeAttribute("name", "random-seed") -.writeAttribute("value", m_config->rngSeed()); -} -} + // Write properties if there are any + if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { + auto properties = xml.scopedElement("properties"); + if (m_config->hasTestFilters()) { + xml.scopedElement("property") + .writeAttribute("name", "filters") + .writeAttribute("value", serializeFilters(m_config->getTestsOrTags())); + } + if (m_config->rngSeed() != 0) { + xml.scopedElement("property") + .writeAttribute("name", "random-seed") + .writeAttribute("value", m_config->rngSeed()); + } + } -// Write test cases -for( auto const& child : groupNode.children ) -writeTestCase( *child ); + // Write test cases + for (auto const& child : groupNode.children) + writeTestCase(*child); -xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline ); -xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline ); -} + xml.scopedElement("system-out").writeText(trim(stdOutForSuite), XmlFormatting::Newline); + xml.scopedElement("system-err").writeText(trim(stdErrForSuite), XmlFormatting::Newline); + } -void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { -TestCaseStats const& stats = testCaseNode.value; + void JunitReporter::writeTestCase(TestCaseNode const& testCaseNode) { + TestCaseStats const& stats = testCaseNode.value; -// All test cases have exactly one section - which represents the -// test case itself. That section may have 0-n nested sections -assert( testCaseNode.children.size() == 1 ); -SectionNode const& rootSection = *testCaseNode.children.front(); + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert(testCaseNode.children.size() == 1); + SectionNode const& rootSection = *testCaseNode.children.front(); -std::string className = stats.testInfo.className; + std::string className = stats.testInfo.className; -if( className.empty() ) { -className = fileNameTag(stats.testInfo.tags); -if ( className.empty() ) -className = "global"; -} + if (className.empty()) { + className = fileNameTag(stats.testInfo.tags); + if (className.empty()) + className = "global"; + } -if ( !m_config->name().empty() ) -className = m_config->name() + "." + className; + if (!m_config->name().empty()) + className = m_config->name() + "." + className; -writeSection( className, "", rootSection ); -} + writeSection(className, "", rootSection); + } -void JunitReporter::writeSection( std::string const& className, -std::string const& rootName, -SectionNode const& sectionNode ) { -std::string name = trim( sectionNode.stats.sectionInfo.name ); -if( !rootName.empty() ) -name = rootName + '/' + name; + void JunitReporter::writeSection(std::string const& className, std::string const& rootName, + SectionNode const& sectionNode) { + std::string name = trim(sectionNode.stats.sectionInfo.name); + if (!rootName.empty()) + name = rootName + '/' + name; -if( !sectionNode.assertions.empty() || -!sectionNode.stdOut.empty() || -!sectionNode.stdErr.empty() ) { -XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); -if( className.empty() ) { -xml.writeAttribute( "classname", name ); -xml.writeAttribute( "name", "root" ); -} -else { -xml.writeAttribute( "classname", className ); -xml.writeAttribute( "name", name ); -} -xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + if (!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) { + XmlWriter::ScopedElement e = xml.scopedElement("testcase"); + if (className.empty()) { + xml.writeAttribute("classname", name); + xml.writeAttribute("name", "root"); + } else { + xml.writeAttribute("classname", className); + xml.writeAttribute("name", name); + } + xml.writeAttribute("time", ::Catch::Detail::stringify(sectionNode.stats.durationInSeconds)); -writeAssertions( sectionNode ); + writeAssertions(sectionNode); -if( !sectionNode.stdOut.empty() ) -xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline ); -if( !sectionNode.stdErr.empty() ) -xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline ); -} -for( auto const& childNode : sectionNode.childSections ) -if( className.empty() ) -writeSection( name, "", *childNode ); -else -writeSection( className, name, *childNode ); -} + if (!sectionNode.stdOut.empty()) + xml.scopedElement("system-out").writeText(trim(sectionNode.stdOut), XmlFormatting::Newline); + if (!sectionNode.stdErr.empty()) + xml.scopedElement("system-err").writeText(trim(sectionNode.stdErr), XmlFormatting::Newline); + } + for (auto const& childNode : sectionNode.childSections) + if (className.empty()) + writeSection(name, "", *childNode); + else + writeSection(className, name, *childNode); + } -void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { -for( auto const& assertion : sectionNode.assertions ) -writeAssertion( assertion ); -} + void JunitReporter::writeAssertions(SectionNode const& sectionNode) { + for (auto const& assertion : sectionNode.assertions) + writeAssertion(assertion); + } -void JunitReporter::writeAssertion( AssertionStats const& stats ) { -AssertionResult const& result = stats.assertionResult; -if( !result.isOk() ) { -std::string elementName; -switch( result.getResultType() ) { -case ResultWas::ThrewException: -case ResultWas::FatalErrorCondition: -elementName = "error"; -break; -case ResultWas::ExplicitFailure: -elementName = "failure"; -break; -case ResultWas::ExpressionFailed: -elementName = "failure"; -break; -case ResultWas::DidntThrowException: -elementName = "failure"; -break; + void JunitReporter::writeAssertion(AssertionStats const& stats) { + AssertionResult const& result = stats.assertionResult; + if (!result.isOk()) { + std::string elementName; + switch (result.getResultType()) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: elementName = "error"; break; + case ResultWas::ExplicitFailure: elementName = "failure"; break; + case ResultWas::ExpressionFailed: elementName = "failure"; break; + case ResultWas::DidntThrowException: elementName = "failure"; break; -// We should never see these here: -case ResultWas::Info: -case ResultWas::Warning: -case ResultWas::Ok: -case ResultWas::Unknown: -case ResultWas::FailureBit: -case ResultWas::Exception: -elementName = "internalError"; -break; -} + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: elementName = "internalError"; break; + } -XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + XmlWriter::ScopedElement e = xml.scopedElement(elementName); -xml.writeAttribute( "message", result.getExpression() ); -xml.writeAttribute( "type", result.getTestMacroName() ); + xml.writeAttribute("message", result.getExpression()); + xml.writeAttribute("type", result.getTestMacroName()); -ReusableStringStream rss; -if (stats.totals.assertions.total() > 0) { -rss << "FAILED" << ":\n"; -if (result.hasExpression()) { -rss << " "; -rss << result.getExpressionInMacro(); -rss << '\n'; -} -if (result.hasExpandedExpression()) { -rss << "with expansion:\n"; -rss << Column(result.getExpandedExpression()).indent(2) << '\n'; -} -} else { -rss << '\n'; -} + ReusableStringStream rss; + if (stats.totals.assertions.total() > 0) { + rss << "FAILED" + << ":\n"; + if (result.hasExpression()) { + rss << " "; + rss << result.getExpressionInMacro(); + rss << '\n'; + } + if (result.hasExpandedExpression()) { + rss << "with expansion:\n"; + rss << Column(result.getExpandedExpression()).indent(2) << '\n'; + } + } else { + rss << '\n'; + } -if( !result.getMessage().empty() ) -rss << result.getMessage() << '\n'; -for( auto const& msg : stats.infoMessages ) -if( msg.type == ResultWas::Info ) -rss << msg.message << '\n'; + if (!result.getMessage().empty()) + rss << result.getMessage() << '\n'; + for (auto const& msg : stats.infoMessages) + if (msg.type == ResultWas::Info) + rss << msg.message << '\n'; -rss << "at " << result.getSourceInfo(); -xml.writeText( rss.str(), XmlFormatting::Newline ); -} -} + rss << "at " << result.getSourceInfo(); + xml.writeText(rss.str(), XmlFormatting::Newline); + } + } -CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + CATCH_REGISTER_REPORTER("junit", JunitReporter) } // end namespace Catch // end catch_reporter_junit.cpp @@ -16725,152 +15870,146 @@ CATCH_REGISTER_REPORTER( "junit", JunitReporter ) namespace Catch { -ListeningReporter::ListeningReporter() { -// We will assume that listeners will always want all assertions -m_preferences.shouldReportAllAssertions = true; -} + ListeningReporter::ListeningReporter() { + // We will assume that listeners will always want all assertions + m_preferences.shouldReportAllAssertions = true; + } -void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { -m_listeners.push_back( std::move( listener ) ); -} + void ListeningReporter::addListener(IStreamingReporterPtr&& listener) { + m_listeners.push_back(std::move(listener)); + } -void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { -assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); -m_reporter = std::move( reporter ); -m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; -} + void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { + assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); + m_reporter = std::move(reporter); + m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; + } -ReporterPreferences ListeningReporter::getPreferences() const { -return m_preferences; -} + ReporterPreferences ListeningReporter::getPreferences() const { return m_preferences; } -std::set ListeningReporter::getSupportedVerbosities() { -return std::set{ }; -} + std::set ListeningReporter::getSupportedVerbosities() { return std::set{}; } -void ListeningReporter::noMatchingTestCases( std::string const& spec ) { -for ( auto const& listener : m_listeners ) { -listener->noMatchingTestCases( spec ); -} -m_reporter->noMatchingTestCases( spec ); -} + void ListeningReporter::noMatchingTestCases(std::string const& spec) { + for (auto const& listener : m_listeners) { + listener->noMatchingTestCases(spec); + } + m_reporter->noMatchingTestCases(spec); + } -void ListeningReporter::reportInvalidArguments(std::string const&arg){ -for ( auto const& listener : m_listeners ) { -listener->reportInvalidArguments( arg ); -} -m_reporter->reportInvalidArguments( arg ); -} + void ListeningReporter::reportInvalidArguments(std::string const& arg) { + for (auto const& listener : m_listeners) { + listener->reportInvalidArguments(arg); + } + m_reporter->reportInvalidArguments(arg); + } #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -void ListeningReporter::benchmarkPreparing( std::string const& name ) { -for (auto const& listener : m_listeners) { -listener->benchmarkPreparing(name); -} -m_reporter->benchmarkPreparing(name); -} -void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { -for ( auto const& listener : m_listeners ) { -listener->benchmarkStarting( benchmarkInfo ); -} -m_reporter->benchmarkStarting( benchmarkInfo ); -} -void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) { -for ( auto const& listener : m_listeners ) { -listener->benchmarkEnded( benchmarkStats ); -} -m_reporter->benchmarkEnded( benchmarkStats ); -} + void ListeningReporter::benchmarkPreparing(std::string const& name) { + for (auto const& listener : m_listeners) { + listener->benchmarkPreparing(name); + } + m_reporter->benchmarkPreparing(name); + } + void ListeningReporter::benchmarkStarting(BenchmarkInfo const& benchmarkInfo) { + for (auto const& listener : m_listeners) { + listener->benchmarkStarting(benchmarkInfo); + } + m_reporter->benchmarkStarting(benchmarkInfo); + } + void ListeningReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { + for (auto const& listener : m_listeners) { + listener->benchmarkEnded(benchmarkStats); + } + m_reporter->benchmarkEnded(benchmarkStats); + } -void ListeningReporter::benchmarkFailed( std::string const& error ) { -for (auto const& listener : m_listeners) { -listener->benchmarkFailed(error); -} -m_reporter->benchmarkFailed(error); -} + void ListeningReporter::benchmarkFailed(std::string const& error) { + for (auto const& listener : m_listeners) { + listener->benchmarkFailed(error); + } + m_reporter->benchmarkFailed(error); + } #endif // CATCH_CONFIG_ENABLE_BENCHMARKING -void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { -for ( auto const& listener : m_listeners ) { -listener->testRunStarting( testRunInfo ); -} -m_reporter->testRunStarting( testRunInfo ); -} + void ListeningReporter::testRunStarting(TestRunInfo const& testRunInfo) { + for (auto const& listener : m_listeners) { + listener->testRunStarting(testRunInfo); + } + m_reporter->testRunStarting(testRunInfo); + } -void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { -for ( auto const& listener : m_listeners ) { -listener->testGroupStarting( groupInfo ); -} -m_reporter->testGroupStarting( groupInfo ); -} + void ListeningReporter::testGroupStarting(GroupInfo const& groupInfo) { + for (auto const& listener : m_listeners) { + listener->testGroupStarting(groupInfo); + } + m_reporter->testGroupStarting(groupInfo); + } -void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { -for ( auto const& listener : m_listeners ) { -listener->testCaseStarting( testInfo ); -} -m_reporter->testCaseStarting( testInfo ); -} + void ListeningReporter::testCaseStarting(TestCaseInfo const& testInfo) { + for (auto const& listener : m_listeners) { + listener->testCaseStarting(testInfo); + } + m_reporter->testCaseStarting(testInfo); + } -void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { -for ( auto const& listener : m_listeners ) { -listener->sectionStarting( sectionInfo ); -} -m_reporter->sectionStarting( sectionInfo ); -} + void ListeningReporter::sectionStarting(SectionInfo const& sectionInfo) { + for (auto const& listener : m_listeners) { + listener->sectionStarting(sectionInfo); + } + m_reporter->sectionStarting(sectionInfo); + } -void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { -for ( auto const& listener : m_listeners ) { -listener->assertionStarting( assertionInfo ); -} -m_reporter->assertionStarting( assertionInfo ); -} + void ListeningReporter::assertionStarting(AssertionInfo const& assertionInfo) { + for (auto const& listener : m_listeners) { + listener->assertionStarting(assertionInfo); + } + m_reporter->assertionStarting(assertionInfo); + } -// The return value indicates if the messages buffer should be cleared: -bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { -for( auto const& listener : m_listeners ) { -static_cast( listener->assertionEnded( assertionStats ) ); -} -return m_reporter->assertionEnded( assertionStats ); -} + // The return value indicates if the messages buffer should be cleared: + bool ListeningReporter::assertionEnded(AssertionStats const& assertionStats) { + for (auto const& listener : m_listeners) { + static_cast(listener->assertionEnded(assertionStats)); + } + return m_reporter->assertionEnded(assertionStats); + } -void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { -for ( auto const& listener : m_listeners ) { -listener->sectionEnded( sectionStats ); -} -m_reporter->sectionEnded( sectionStats ); -} + void ListeningReporter::sectionEnded(SectionStats const& sectionStats) { + for (auto const& listener : m_listeners) { + listener->sectionEnded(sectionStats); + } + m_reporter->sectionEnded(sectionStats); + } -void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { -for ( auto const& listener : m_listeners ) { -listener->testCaseEnded( testCaseStats ); -} -m_reporter->testCaseEnded( testCaseStats ); -} + void ListeningReporter::testCaseEnded(TestCaseStats const& testCaseStats) { + for (auto const& listener : m_listeners) { + listener->testCaseEnded(testCaseStats); + } + m_reporter->testCaseEnded(testCaseStats); + } -void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { -for ( auto const& listener : m_listeners ) { -listener->testGroupEnded( testGroupStats ); -} -m_reporter->testGroupEnded( testGroupStats ); -} + void ListeningReporter::testGroupEnded(TestGroupStats const& testGroupStats) { + for (auto const& listener : m_listeners) { + listener->testGroupEnded(testGroupStats); + } + m_reporter->testGroupEnded(testGroupStats); + } -void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { -for ( auto const& listener : m_listeners ) { -listener->testRunEnded( testRunStats ); -} -m_reporter->testRunEnded( testRunStats ); -} + void ListeningReporter::testRunEnded(TestRunStats const& testRunStats) { + for (auto const& listener : m_listeners) { + listener->testRunEnded(testRunStats); + } + m_reporter->testRunEnded(testRunStats); + } -void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { -for ( auto const& listener : m_listeners ) { -listener->skipTest( testInfo ); -} -m_reporter->skipTest( testInfo ); -} + void ListeningReporter::skipTest(TestCaseInfo const& testInfo) { + for (auto const& listener : m_listeners) { + listener->skipTest(testInfo); + } + m_reporter->skipTest(testInfo); + } -bool ListeningReporter::isMulti() const { -return true; -} + bool ListeningReporter::isMulti() const { return true; } } // end namespace Catch // end catch_reporter_listening.cpp @@ -16878,257 +16017,233 @@ return true; #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch +#pragma warning(disable : 4061) // Not all labels are EXPLICITLY handled in switch // Note that 4062 (not all labels are handled // and default is missing) is enabled #endif namespace Catch { -XmlReporter::XmlReporter( ReporterConfig const& _config ) -: StreamingReporterBase( _config ), -m_xml(_config.stream()) -{ -m_reporterPrefs.shouldRedirectStdOut = true; -m_reporterPrefs.shouldReportAllAssertions = true; -} + XmlReporter::XmlReporter(ReporterConfig const& _config) : StreamingReporterBase(_config), m_xml(_config.stream()) { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } -XmlReporter::~XmlReporter() = default; + XmlReporter::~XmlReporter() = default; -std::string XmlReporter::getDescription() { -return "Reports test results as an XML document"; -} + std::string XmlReporter::getDescription() { return "Reports test results as an XML document"; } -std::string XmlReporter::getStylesheetRef() const { -return std::string(); -} + std::string XmlReporter::getStylesheetRef() const { return std::string(); } -void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { -m_xml -.writeAttribute( "filename", sourceInfo.file ) -.writeAttribute( "line", sourceInfo.line ); -} + void XmlReporter::writeSourceInfo(SourceLineInfo const& sourceInfo) { + m_xml.writeAttribute("filename", sourceInfo.file).writeAttribute("line", sourceInfo.line); + } -void XmlReporter::noMatchingTestCases( std::string const& s ) { -StreamingReporterBase::noMatchingTestCases( s ); -} + void XmlReporter::noMatchingTestCases(std::string const& s) { StreamingReporterBase::noMatchingTestCases(s); } -void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { -StreamingReporterBase::testRunStarting( testInfo ); -std::string stylesheetRef = getStylesheetRef(); -if( !stylesheetRef.empty() ) -m_xml.writeStylesheetRef( stylesheetRef ); -m_xml.startElement( "Catch" ); -if( !m_config->name().empty() ) -m_xml.writeAttribute( "name", m_config->name() ); -if (m_config->testSpec().hasFilters()) -m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) ); -if( m_config->rngSeed() != 0 ) -m_xml.scopedElement( "Randomness" ) -.writeAttribute( "seed", m_config->rngSeed() ); -} + void XmlReporter::testRunStarting(TestRunInfo const& testInfo) { + StreamingReporterBase::testRunStarting(testInfo); + std::string stylesheetRef = getStylesheetRef(); + if (!stylesheetRef.empty()) + m_xml.writeStylesheetRef(stylesheetRef); + m_xml.startElement("Catch"); + if (!m_config->name().empty()) + m_xml.writeAttribute("name", m_config->name()); + if (m_config->testSpec().hasFilters()) + m_xml.writeAttribute("filters", serializeFilters(m_config->getTestsOrTags())); + if (m_config->rngSeed() != 0) + m_xml.scopedElement("Randomness").writeAttribute("seed", m_config->rngSeed()); + } -void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { -StreamingReporterBase::testGroupStarting( groupInfo ); -m_xml.startElement( "Group" ) -.writeAttribute( "name", groupInfo.name ); -} + void XmlReporter::testGroupStarting(GroupInfo const& groupInfo) { + StreamingReporterBase::testGroupStarting(groupInfo); + m_xml.startElement("Group").writeAttribute("name", groupInfo.name); + } -void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { -StreamingReporterBase::testCaseStarting(testInfo); -m_xml.startElement( "TestCase" ) -.writeAttribute( "name", trim( testInfo.name ) ) -.writeAttribute( "description", testInfo.description ) -.writeAttribute( "tags", testInfo.tagsAsString() ); + void XmlReporter::testCaseStarting(TestCaseInfo const& testInfo) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement("TestCase") + .writeAttribute("name", trim(testInfo.name)) + .writeAttribute("description", testInfo.description) + .writeAttribute("tags", testInfo.tagsAsString()); -writeSourceInfo( testInfo.lineInfo ); + writeSourceInfo(testInfo.lineInfo); -if ( m_config->showDurations() == ShowDurations::Always ) -m_testCaseTimer.start(); -m_xml.ensureTagClosed(); -} + if (m_config->showDurations() == ShowDurations::Always) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } -void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { -StreamingReporterBase::sectionStarting( sectionInfo ); -if( m_sectionDepth++ > 0 ) { -m_xml.startElement( "Section" ) -.writeAttribute( "name", trim( sectionInfo.name ) ); -writeSourceInfo( sectionInfo.lineInfo ); -m_xml.ensureTagClosed(); -} -} + void XmlReporter::sectionStarting(SectionInfo const& sectionInfo) { + StreamingReporterBase::sectionStarting(sectionInfo); + if (m_sectionDepth++ > 0) { + m_xml.startElement("Section").writeAttribute("name", trim(sectionInfo.name)); + writeSourceInfo(sectionInfo.lineInfo); + m_xml.ensureTagClosed(); + } + } -void XmlReporter::assertionStarting( AssertionInfo const& ) { } + void XmlReporter::assertionStarting(AssertionInfo const&) {} -bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { + bool XmlReporter::assertionEnded(AssertionStats const& assertionStats) { -AssertionResult const& result = assertionStats.assertionResult; + AssertionResult const& result = assertionStats.assertionResult; -bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); -if( includeResults || result.getResultType() == ResultWas::Warning ) { -// Print any info messages in tags. -for( auto const& msg : assertionStats.infoMessages ) { -if( msg.type == ResultWas::Info && includeResults ) { -m_xml.scopedElement( "Info" ) -.writeText( msg.message ); -} else if ( msg.type == ResultWas::Warning ) { -m_xml.scopedElement( "Warning" ) -.writeText( msg.message ); -} -} -} + if (includeResults || result.getResultType() == ResultWas::Warning) { + // Print any info messages in tags. + for (auto const& msg : assertionStats.infoMessages) { + if (msg.type == ResultWas::Info && includeResults) { + m_xml.scopedElement("Info").writeText(msg.message); + } else if (msg.type == ResultWas::Warning) { + m_xml.scopedElement("Warning").writeText(msg.message); + } + } + } -// Drop out if result was successful but we're not printing them. -if( !includeResults && result.getResultType() != ResultWas::Warning ) -return true; + // Drop out if result was successful but we're not printing them. + if (!includeResults && result.getResultType() != ResultWas::Warning) + return true; -// Print the expression if there is one. -if( result.hasExpression() ) { -m_xml.startElement( "Expression" ) -.writeAttribute( "success", result.succeeded() ) -.writeAttribute( "type", result.getTestMacroName() ); + // Print the expression if there is one. + if (result.hasExpression()) { + m_xml.startElement("Expression") + .writeAttribute("success", result.succeeded()) + .writeAttribute("type", result.getTestMacroName()); -writeSourceInfo( result.getSourceInfo() ); + writeSourceInfo(result.getSourceInfo()); -m_xml.scopedElement( "Original" ) -.writeText( result.getExpression() ); -m_xml.scopedElement( "Expanded" ) -.writeText( result.getExpandedExpression() ); -} + m_xml.scopedElement("Original").writeText(result.getExpression()); + m_xml.scopedElement("Expanded").writeText(result.getExpandedExpression()); + } -// And... Print a result applicable to each result type. -switch( result.getResultType() ) { -case ResultWas::ThrewException: -m_xml.startElement( "Exception" ); -writeSourceInfo( result.getSourceInfo() ); -m_xml.writeText( result.getMessage() ); -m_xml.endElement(); -break; -case ResultWas::FatalErrorCondition: -m_xml.startElement( "FatalErrorCondition" ); -writeSourceInfo( result.getSourceInfo() ); -m_xml.writeText( result.getMessage() ); -m_xml.endElement(); -break; -case ResultWas::Info: -m_xml.scopedElement( "Info" ) -.writeText( result.getMessage() ); -break; -case ResultWas::Warning: -// Warning will already have been written -break; -case ResultWas::ExplicitFailure: -m_xml.startElement( "Failure" ); -writeSourceInfo( result.getSourceInfo() ); -m_xml.writeText( result.getMessage() ); -m_xml.endElement(); -break; -default: -break; -} + // And... Print a result applicable to each result type. + switch (result.getResultType()) { + case ResultWas::ThrewException: + m_xml.startElement("Exception"); + writeSourceInfo(result.getSourceInfo()); + m_xml.writeText(result.getMessage()); + m_xml.endElement(); + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement("FatalErrorCondition"); + writeSourceInfo(result.getSourceInfo()); + m_xml.writeText(result.getMessage()); + m_xml.endElement(); + break; + case ResultWas::Info: m_xml.scopedElement("Info").writeText(result.getMessage()); break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement("Failure"); + writeSourceInfo(result.getSourceInfo()); + m_xml.writeText(result.getMessage()); + m_xml.endElement(); + break; + default: break; + } -if( result.hasExpression() ) -m_xml.endElement(); + if (result.hasExpression()) + m_xml.endElement(); -return true; -} + return true; + } -void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { -StreamingReporterBase::sectionEnded( sectionStats ); -if( --m_sectionDepth > 0 ) { -XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); -e.writeAttribute( "successes", sectionStats.assertions.passed ); -e.writeAttribute( "failures", sectionStats.assertions.failed ); -e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + void XmlReporter::sectionEnded(SectionStats const& sectionStats) { + StreamingReporterBase::sectionEnded(sectionStats); + if (--m_sectionDepth > 0) { + XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResults"); + e.writeAttribute("successes", sectionStats.assertions.passed); + e.writeAttribute("failures", sectionStats.assertions.failed); + e.writeAttribute("expectedFailures", sectionStats.assertions.failedButOk); -if ( m_config->showDurations() == ShowDurations::Always ) -e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + if (m_config->showDurations() == ShowDurations::Always) + e.writeAttribute("durationInSeconds", sectionStats.durationInSeconds); -m_xml.endElement(); -} -} + m_xml.endElement(); + } + } -void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { -StreamingReporterBase::testCaseEnded( testCaseStats ); -XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); -e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + void XmlReporter::testCaseEnded(TestCaseStats const& testCaseStats) { + StreamingReporterBase::testCaseEnded(testCaseStats); + XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResult"); + e.writeAttribute("success", testCaseStats.totals.assertions.allOk()); -if ( m_config->showDurations() == ShowDurations::Always ) -e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + if (m_config->showDurations() == ShowDurations::Always) + e.writeAttribute("durationInSeconds", m_testCaseTimer.getElapsedSeconds()); -if( !testCaseStats.stdOut.empty() ) -m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); -if( !testCaseStats.stdErr.empty() ) -m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); + if (!testCaseStats.stdOut.empty()) + m_xml.scopedElement("StdOut").writeText(trim(testCaseStats.stdOut), XmlFormatting::Newline); + if (!testCaseStats.stdErr.empty()) + m_xml.scopedElement("StdErr").writeText(trim(testCaseStats.stdErr), XmlFormatting::Newline); -m_xml.endElement(); -} + m_xml.endElement(); + } -void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { -StreamingReporterBase::testGroupEnded( testGroupStats ); -// TODO: Check testGroupStats.aborting and act accordingly. -m_xml.scopedElement( "OverallResults" ) -.writeAttribute( "successes", testGroupStats.totals.assertions.passed ) -.writeAttribute( "failures", testGroupStats.totals.assertions.failed ) -.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); -m_xml.endElement(); -} + void XmlReporter::testGroupEnded(TestGroupStats const& testGroupStats) { + StreamingReporterBase::testGroupEnded(testGroupStats); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement("OverallResults") + .writeAttribute("successes", testGroupStats.totals.assertions.passed) + .writeAttribute("failures", testGroupStats.totals.assertions.failed) + .writeAttribute("expectedFailures", testGroupStats.totals.assertions.failedButOk); + m_xml.endElement(); + } -void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { -StreamingReporterBase::testRunEnded( testRunStats ); -m_xml.scopedElement( "OverallResults" ) -.writeAttribute( "successes", testRunStats.totals.assertions.passed ) -.writeAttribute( "failures", testRunStats.totals.assertions.failed ) -.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); -m_xml.endElement(); -} + void XmlReporter::testRunEnded(TestRunStats const& testRunStats) { + StreamingReporterBase::testRunEnded(testRunStats); + m_xml.scopedElement("OverallResults") + .writeAttribute("successes", testRunStats.totals.assertions.passed) + .writeAttribute("failures", testRunStats.totals.assertions.failed) + .writeAttribute("expectedFailures", testRunStats.totals.assertions.failedButOk); + m_xml.endElement(); + } #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -void XmlReporter::benchmarkPreparing(std::string const& name) { -m_xml.startElement("BenchmarkResults") -.writeAttribute("name", name); -} + void XmlReporter::benchmarkPreparing(std::string const& name) { + m_xml.startElement("BenchmarkResults").writeAttribute("name", name); + } -void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) { -m_xml.writeAttribute("samples", info.samples) -.writeAttribute("resamples", info.resamples) -.writeAttribute("iterations", info.iterations) -.writeAttribute("clockResolution", static_cast(info.clockResolution)) -.writeAttribute("estimatedDuration", static_cast(info.estimatedDuration)) -.writeComment("All values in nano seconds"); -} + void XmlReporter::benchmarkStarting(BenchmarkInfo const& info) { + m_xml.writeAttribute("samples", info.samples) + .writeAttribute("resamples", info.resamples) + .writeAttribute("iterations", info.iterations) + .writeAttribute("clockResolution", static_cast(info.clockResolution)) + .writeAttribute("estimatedDuration", static_cast(info.estimatedDuration)) + .writeComment("All values in nano seconds"); + } -void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { -m_xml.startElement("mean") -.writeAttribute("value", static_cast(benchmarkStats.mean.point.count())) -.writeAttribute("lowerBound", static_cast(benchmarkStats.mean.lower_bound.count())) -.writeAttribute("upperBound", static_cast(benchmarkStats.mean.upper_bound.count())) -.writeAttribute("ci", benchmarkStats.mean.confidence_interval); -m_xml.endElement(); -m_xml.startElement("standardDeviation") -.writeAttribute("value", benchmarkStats.standardDeviation.point.count()) -.writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count()) -.writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count()) -.writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval); -m_xml.endElement(); -m_xml.startElement("outliers") -.writeAttribute("variance", benchmarkStats.outlierVariance) -.writeAttribute("lowMild", benchmarkStats.outliers.low_mild) -.writeAttribute("lowSevere", benchmarkStats.outliers.low_severe) -.writeAttribute("highMild", benchmarkStats.outliers.high_mild) -.writeAttribute("highSevere", benchmarkStats.outliers.high_severe); -m_xml.endElement(); -m_xml.endElement(); -} + void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { + m_xml.startElement("mean") + .writeAttribute("value", static_cast(benchmarkStats.mean.point.count())) + .writeAttribute("lowerBound", static_cast(benchmarkStats.mean.lower_bound.count())) + .writeAttribute("upperBound", static_cast(benchmarkStats.mean.upper_bound.count())) + .writeAttribute("ci", benchmarkStats.mean.confidence_interval); + m_xml.endElement(); + m_xml.startElement("standardDeviation") + .writeAttribute("value", benchmarkStats.standardDeviation.point.count()) + .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count()) + .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count()) + .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval); + m_xml.endElement(); + m_xml.startElement("outliers") + .writeAttribute("variance", benchmarkStats.outlierVariance) + .writeAttribute("lowMild", benchmarkStats.outliers.low_mild) + .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe) + .writeAttribute("highMild", benchmarkStats.outliers.high_mild) + .writeAttribute("highSevere", benchmarkStats.outliers.high_severe); + m_xml.endElement(); + m_xml.endElement(); + } -void XmlReporter::benchmarkFailed(std::string const &error) { -m_xml.scopedElement("failed"). -writeAttribute("message", error); -m_xml.endElement(); -} + void XmlReporter::benchmarkFailed(std::string const& error) { + m_xml.scopedElement("failed").writeAttribute("message", error); + m_xml.endElement(); + } #endif // CATCH_CONFIG_ENABLE_BENCHMARKING -CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + CATCH_REGISTER_REPORTER("xml", XmlReporter) } // end namespace Catch @@ -17138,7 +16253,7 @@ CATCH_REGISTER_REPORTER( "xml", XmlReporter ) // end catch_reporter_xml.cpp namespace Catch { -LeakDetector leakDetector; + LeakDetector leakDetector; } #ifdef __clang__ diff --git a/src/Battling/EventHooks/EventData.hpp b/src/Battling/EventHooks/EventData.hpp index 1c7d4cd..6f00c82 100644 --- a/src/Battling/EventHooks/EventData.hpp +++ b/src/Battling/EventHooks/EventData.hpp @@ -10,7 +10,7 @@ namespace CreatureLib::Battling { class EventData { public: virtual ~EventData() = default; - virtual EventDataKind GetKind() const = 0; + virtual EventDataKind GetKind() const noexcept = 0; }; class DamageEvent : public EventData { @@ -20,13 +20,13 @@ namespace CreatureLib::Battling { uint32_t _newHealth; public: - DamageEvent(Creature* c, DamageSource s, uint32_t oHealth, uint32_t newHealth) + DamageEvent(Creature* c, DamageSource s, uint32_t oHealth, uint32_t newHealth) noexcept : _creature(c), _damageSource(s), _originalHealth(oHealth), _newHealth(newHealth) {} - EventDataKind GetKind() const override { return EventDataKind ::Damage; } - Creature* GetCreature() const { return _creature; } - DamageSource GetDamageSource() const { return _damageSource; } - uint32_t GetOriginalHealth() const { return _originalHealth; } - uint32_t GetNewHealth() const { return _newHealth; } + EventDataKind GetKind() const noexcept override { return EventDataKind ::Damage; } + Creature* GetCreature() const noexcept { return _creature; } + DamageSource GetDamageSource() const noexcept { return _damageSource; } + uint32_t GetOriginalHealth() const noexcept { return _originalHealth; } + uint32_t GetNewHealth() const noexcept { return _newHealth; } }; class HealEvent : public EventData { @@ -35,30 +35,30 @@ namespace CreatureLib::Battling { uint32_t _newHealth; public: - HealEvent(Creature* c, uint32_t oHealth, uint32_t newHealth) + HealEvent(Creature* c, uint32_t oHealth, uint32_t newHealth) noexcept : _creature(c), _originalHealth(oHealth), _newHealth(newHealth) {} - EventDataKind GetKind() const override { return EventDataKind ::Heal; } - Creature* GetCreature() const { return _creature; } - uint32_t GetOriginalHealth() const { return _originalHealth; } - uint32_t GetNewHealth() const { return _newHealth; } + EventDataKind GetKind() const noexcept override { return EventDataKind ::Heal; } + Creature* GetCreature() const noexcept { return _creature; } + uint32_t GetOriginalHealth() const noexcept { return _originalHealth; } + uint32_t GetNewHealth() const noexcept { return _newHealth; } }; class FaintEvent : public EventData { Creature* _creature; public: - FaintEvent(Creature* c) : _creature(c) {} - EventDataKind GetKind() const override { return EventDataKind ::Faint; } - Creature* GetCreature() const { return _creature; } + FaintEvent(Creature* c) noexcept : _creature(c) {} + EventDataKind GetKind() const noexcept override { return EventDataKind ::Faint; } + Creature* GetCreature() const noexcept { return _creature; } }; class DisplayTextEvent : public EventData { const std::string _text; public: - DisplayTextEvent(const std::string& text) : _text(text) {} - EventDataKind GetKind() const override { return EventDataKind ::DisplayText; } - const std::string& GetText() const { return _text; } + DisplayTextEvent(const std::string& text) noexcept : _text(text) {} + EventDataKind GetKind() const noexcept override { return EventDataKind ::DisplayText; } + const std::string& GetText() const noexcept { return _text; } }; } diff --git a/src/Battling/Library/BattleLibrary.cpp b/src/Battling/Library/BattleLibrary.cpp index 0cb0104..bcd14b6 100644 --- a/src/Battling/Library/BattleLibrary.cpp +++ b/src/Battling/Library/BattleLibrary.cpp @@ -17,25 +17,31 @@ BattleLibrary::~BattleLibrary() { delete _miscLibrary; } -const CreatureLib::Library::LibrarySettings* BattleLibrary::GetSettings() const { return _staticLib->GetSettings(); } +const CreatureLib::Library::LibrarySettings* BattleLibrary::GetSettings() const noexcept { + return _staticLib->GetSettings(); +} -const BattleStatCalculator* BattleLibrary::GetStatCalculator() const { return _statCalculator; } +const BattleStatCalculator* BattleLibrary::GetStatCalculator() const noexcept { return _statCalculator; } -const CreatureLib::Library::SpeciesLibrary* BattleLibrary::GetSpeciesLibrary() const { +const CreatureLib::Library::SpeciesLibrary* BattleLibrary::GetSpeciesLibrary() const noexcept { return _staticLib->GetSpeciesLibrary(); } -const CreatureLib::Library::ItemLibrary* BattleLibrary::GetItemLibrary() const { return _staticLib->GetItemLibrary(); } +const CreatureLib::Library::ItemLibrary* BattleLibrary::GetItemLibrary() const noexcept { + return _staticLib->GetItemLibrary(); +} -const CreatureLib::Library::AttackLibrary* BattleLibrary::GetAttackLibrary() const { +const CreatureLib::Library::AttackLibrary* BattleLibrary::GetAttackLibrary() const noexcept { return _staticLib->GetAttackLibrary(); } -const CreatureLib::Library::TypeLibrary* BattleLibrary::GetTypeLibrary() const { return _staticLib->GetTypeLibrary(); } +const CreatureLib::Library::TypeLibrary* BattleLibrary::GetTypeLibrary() const noexcept { + return _staticLib->GetTypeLibrary(); +} -const DamageLibrary* BattleLibrary::GetDamageLibrary() const { return _damageLibrary; } +const DamageLibrary* BattleLibrary::GetDamageLibrary() const noexcept { return _damageLibrary; } -const MiscLibrary* BattleLibrary::GetMiscLibrary() const { return _miscLibrary; } +const MiscLibrary* BattleLibrary::GetMiscLibrary() const noexcept { return _miscLibrary; } Script* BattleLibrary::LoadScript(ScriptCategory category, const ConstString& scriptName) const { return _scriptResolver->LoadScript(category, scriptName); diff --git a/src/Battling/Library/BattleLibrary.hpp b/src/Battling/Library/BattleLibrary.hpp index bc3add5..cc5ecd3 100644 --- a/src/Battling/Library/BattleLibrary.hpp +++ b/src/Battling/Library/BattleLibrary.hpp @@ -23,21 +23,21 @@ namespace CreatureLib::Battling { DamageLibrary* damageLibrary, ExperienceLibrary* experienceLibrary, ScriptResolver* scriptResolver, MiscLibrary* miscLibrary); ~BattleLibrary(); - inline const Library::DataLibrary* GetStaticLib() const { return _staticLib; } + inline const Library::DataLibrary* GetStaticLib() const noexcept { return _staticLib; } - [[nodiscard]] const Library::LibrarySettings* GetSettings() const; - [[nodiscard]] const Library::SpeciesLibrary* GetSpeciesLibrary() const; - [[nodiscard]] const Library::ItemLibrary* GetItemLibrary() const; - [[nodiscard]] const Library::AttackLibrary* GetAttackLibrary() const; - [[nodiscard]] const Library::TypeLibrary* GetTypeLibrary() const; - [[nodiscard]] const Library::GrowthRateLibrary* GetGrowthRateLibrary() const { + [[nodiscard]] const Library::LibrarySettings* GetSettings() const noexcept; + [[nodiscard]] const Library::SpeciesLibrary* GetSpeciesLibrary() const noexcept; + [[nodiscard]] const Library::ItemLibrary* GetItemLibrary() const noexcept; + [[nodiscard]] const Library::AttackLibrary* GetAttackLibrary() const noexcept; + [[nodiscard]] const Library::TypeLibrary* GetTypeLibrary() const noexcept; + [[nodiscard]] const Library::GrowthRateLibrary* GetGrowthRateLibrary() const noexcept { return _staticLib->GetGrowthRates(); } - [[nodiscard]] const BattleStatCalculator* GetStatCalculator() const; - [[nodiscard]] const DamageLibrary* GetDamageLibrary() const; - [[nodiscard]] const MiscLibrary* GetMiscLibrary() const; - [[nodiscard]] const ExperienceLibrary* GetExperienceLibrary() const { return _experienceLibrary; } + [[nodiscard]] const BattleStatCalculator* GetStatCalculator() const noexcept; + [[nodiscard]] const DamageLibrary* GetDamageLibrary() const noexcept; + [[nodiscard]] const MiscLibrary* GetMiscLibrary() const noexcept; + [[nodiscard]] const ExperienceLibrary* GetExperienceLibrary() const noexcept { return _experienceLibrary; } [[nodiscard]] Script* LoadScript(ScriptCategory category, const ConstString& scriptName) const; }; diff --git a/src/Battling/Models/Battle.cpp b/src/Battling/Models/Battle.cpp index 9302ea5..a8f3155 100644 --- a/src/Battling/Models/Battle.cpp +++ b/src/Battling/Models/Battle.cpp @@ -7,7 +7,7 @@ using namespace CreatureLib; using namespace CreatureLib::Battling; -const BattleLibrary* Battle::GetLibrary() const { return _library; } +const BattleLibrary* Battle::GetLibrary() const noexcept { return _library; } bool Battle::CanUse(const BaseTurnChoice* choice) { AssertNotNull(choice) @@ -69,9 +69,9 @@ void Battle::CheckChoicesSetAndRun() { } } -ChoiceQueue* Battle::GetCurrentTurnQueue() const { return _currentTurnQueue; } +ChoiceQueue* Battle::GetCurrentTurnQueue() const noexcept { return _currentTurnQueue; } -BattleRandom* Battle::GetRandom() { return &_random; } +BattleRandom* Battle::GetRandom() noexcept { return &_random; } bool Battle::CreatureInField(const Creature* creature) const { AssertNotNull(creature) @@ -87,7 +87,6 @@ void Battle::ForceRecall(uint8_t side, uint8_t index) { _sides[side]->SetCreatur void Battle::GetActiveScripts(Arbutils::Collections::List& scripts) { scripts.Append(&_volatile); } void Battle::SwitchCreature(uint8_t sideIndex, uint8_t index, Creature* c) { - AssertNotNull(c) auto side = this->_sides[sideIndex]; side->SetCreature(c, index); } diff --git a/src/Battling/Models/Battle.hpp b/src/Battling/Models/Battle.hpp index 307503f..4684bff 100644 --- a/src/Battling/Models/Battle.hpp +++ b/src/Battling/Models/Battle.hpp @@ -57,18 +57,18 @@ namespace CreatureLib::Battling { delete _currentTurnQueue; } - [[nodiscard]] const BattleLibrary* GetLibrary() const; + [[nodiscard]] const BattleLibrary* GetLibrary() const noexcept; [[nodiscard]] uint32_t GetCurrentTurn() const noexcept { return _currentTurn; } virtual bool CanUse(const BaseTurnChoice* choice); virtual bool TrySetChoice(BaseTurnChoice* choice); - bool CanFlee() const { return _canFlee; } + bool CanFlee() const noexcept { return _canFlee; } void CheckChoicesSetAndRun(); - [[nodiscard]] ChoiceQueue* GetCurrentTurnQueue() const; - BattleRandom* GetRandom(); + [[nodiscard]] ChoiceQueue* GetCurrentTurnQueue() const noexcept; + BattleRandom* GetRandom() noexcept; bool CreatureInField(const Creature* creature) const; @@ -84,12 +84,12 @@ namespace CreatureLib::Battling { void GetActiveScripts(Arbutils::Collections::List& scripts) override; void ValidateBattleState(); - inline bool HasEnded() const { return _hasEnded; } - inline const BattleResult& GetResult() const { return _battleResult; } + inline bool HasEnded() const noexcept { return _hasEnded; } + inline const BattleResult& GetResult() const noexcept { return _battleResult; } - const List& GetSides() const { return _sides; } + const List& GetSides() const noexcept { return _sides; } Script* GetVolatileScript(const ConstString& key) const { return _volatile.Get(key); } - Script* GetVolatileScript(uint32_t keyHash) const { return _volatile.Get(keyHash); } + Script* GetVolatileScript(uint32_t keyHash) const noexcept { return _volatile.Get(keyHash); } void AddVolatileScript(const ConstString& key); void AddVolatileScript(Script* script); void RemoveVolatileScript(const ConstString& name) { _volatile.Remove(name); } diff --git a/src/Battling/Models/BattleResult.hpp b/src/Battling/Models/BattleResult.hpp index ef72405..615e3d9 100644 --- a/src/Battling/Models/BattleResult.hpp +++ b/src/Battling/Models/BattleResult.hpp @@ -16,9 +16,9 @@ namespace CreatureLib::Battling { static BattleResult Empty() { return BattleResult(false, 0); } /// Whether or not the battle has ended with a conclusive result. - bool IsConclusiveResult() const { return _conclusiveResult; } + bool IsConclusiveResult() const noexcept { return _conclusiveResult; } /// Get the index of the side that has won the battle. Only valid if the battle has a conclusive result. - uint8_t GetWinningSide() const { return _winningSide; } + uint8_t GetWinningSide() const noexcept { return _winningSide; } }; } diff --git a/src/Battling/Models/BattleSide.cpp b/src/Battling/Models/BattleSide.cpp index 5dd4eec..d335fc0 100644 --- a/src/Battling/Models/BattleSide.cpp +++ b/src/Battling/Models/BattleSide.cpp @@ -39,14 +39,15 @@ void BattleSide::SetChoice(BaseTurnChoice* choice) { } void BattleSide::SetCreature(Creature* creature, uint8_t index) { - AssertNotNull(creature) auto old = _creatures[index]; if (old != nullptr) { old->SetOnBattleField(false); } _creatures[index] = creature; - creature->SetBattleData(_battle, this); - creature->SetOnBattleField(true); + if (creature != nullptr) { + creature->SetBattleData(_battle, this); + creature->SetOnBattleField(true); + } if (_battle == nullptr) return; for (auto side : _battle->GetSides()) { diff --git a/src/Battling/Models/Creature.cpp b/src/Battling/Models/Creature.cpp index 5e2add3..b682aea 100644 --- a/src/Battling/Models/Creature.cpp +++ b/src/Battling/Models/Creature.cpp @@ -24,7 +24,12 @@ Battling::Creature::Creature(const BattleLibrary* library, const Library::Creatu } void Battling::Creature::ChangeLevelBy(int8_t amount) { - this->_level += amount; + auto level = _level + amount; + if (level > _library->GetSettings()->GetMaximalLevel()) + level = _library->GetSettings()->GetMaximalLevel(); + if (level < 1) + level = 1; + _level = level; _experience = _library->GetGrowthRateLibrary()->CalculateExperience(_species->GetGrowthRate(), _level); RecalculateFlatStats(); } @@ -52,13 +57,17 @@ void Battling::Creature::ChangeStatBoost(Library::Statistic stat, int8_t diffAmo this->RecalculateBoostedStat(stat); } -uint32_t Battling::Creature::GetFlatStat(Library::Statistic stat) const { return _flatStats.GetStat(stat); } +uint32_t Battling::Creature::GetFlatStat(Library::Statistic stat) const noexcept { return _flatStats.GetStat(stat); } -uint32_t Battling::Creature::GetBoostedStat(Library::Statistic stat) const { return _boostedStats.GetStat(stat); } +uint32_t Battling::Creature::GetBoostedStat(Library::Statistic stat) const noexcept { + return _boostedStats.GetStat(stat); +} -uint32_t Battling::Creature::GetBaseStat(Library::Statistic stat) const { return _variant->GetStatistic(stat); } +uint32_t Battling::Creature::GetBaseStat(Library::Statistic stat) const noexcept { + return _variant->GetStatistic(stat); +} -int8_t Battling::Creature::GetStatBoost(Library::Statistic stat) const { return _statBoost.GetStat(stat); } +int8_t Battling::Creature::GetStatBoost(Library::Statistic stat) const noexcept { return _statBoost.GetStat(stat); } void Battling::Creature::RecalculateFlatStats() { auto statCalc = this->_library->GetStatCalculator(); @@ -174,13 +183,13 @@ void Battling::Creature::AddExperience(uint32_t amount) { _experience = exp; _level = level; } -const Library::CreatureSpecies* Battling::Creature::GetDisplaySpecies() const { +const Library::CreatureSpecies* Battling::Creature::GetDisplaySpecies() const noexcept { auto species = _displaySpecies; if (species == nullptr) species = _species; return species; } -const Library::SpeciesVariant* Battling::Creature::GetDisplayVariant() const { +const Library::SpeciesVariant* Battling::Creature::GetDisplayVariant() const noexcept { auto variant = _displayVariant; if (variant == nullptr) variant = _variant; diff --git a/src/Battling/Models/Creature.hpp b/src/Battling/Models/Creature.hpp index f713f4a..e826d28 100644 --- a/src/Battling/Models/Creature.hpp +++ b/src/Battling/Models/Creature.hpp @@ -129,21 +129,21 @@ namespace CreatureLib::Battling { void RemoveVolatileScript(Script* script); bool HasVolatileScript(const ConstString& name) const; - List& GetAttacks() { return _attacks; } + List& GetAttacks() noexcept { return _attacks; } - const Library::CreatureSpecies* GetDisplaySpecies() const; - const Library::SpeciesVariant* GetDisplayVariant() const; + const Library::CreatureSpecies* GetDisplaySpecies() const noexcept; + const Library::SpeciesVariant* GetDisplayVariant() const noexcept; - const void SetDisplaySpecies(const Library::CreatureSpecies* species) { _displaySpecies = species; } - const void SetDisplayVariant(const Library::SpeciesVariant* variant) { _displayVariant = variant; }; + const void SetDisplaySpecies(const Library::CreatureSpecies* species) noexcept { _displaySpecies = species; } + const void SetDisplayVariant(const Library::SpeciesVariant* variant) noexcept { _displayVariant = variant; }; // region Stat APIs void ChangeStatBoost(Library::Statistic stat, int8_t diffAmount); - [[nodiscard]] uint32_t GetFlatStat(Library::Statistic stat) const; - [[nodiscard]] uint32_t GetBoostedStat(Library::Statistic stat) const; - [[nodiscard]] uint32_t GetBaseStat(Library::Statistic stat) const; - [[nodiscard]] int8_t GetStatBoost(Library::Statistic stat) const; + [[nodiscard]] uint32_t GetFlatStat(Library::Statistic stat) const noexcept; + [[nodiscard]] uint32_t GetBoostedStat(Library::Statistic stat) const noexcept; + [[nodiscard]] uint32_t GetBaseStat(Library::Statistic stat) const noexcept; + [[nodiscard]] int8_t GetStatBoost(Library::Statistic stat) const noexcept; void RecalculateFlatStats(); void RecalculateBoostedStats(); void RecalculateFlatStat(Library::Statistic); diff --git a/src/Battling/Models/CreatureIndex.hpp b/src/Battling/Models/CreatureIndex.hpp index 3c541a5..70faaf4 100644 --- a/src/Battling/Models/CreatureIndex.hpp +++ b/src/Battling/Models/CreatureIndex.hpp @@ -10,16 +10,18 @@ namespace CreatureLib::Battling { uint8_t _creature; public: - CreatureIndex() : _side(0), _creature(0) {} - CreatureIndex(uint8_t side, uint8_t creature) : _side(side), _creature(creature) {} + CreatureIndex() noexcept : _side(0), _creature(0) {} + CreatureIndex(uint8_t side, uint8_t creature) noexcept : _side(side), _creature(creature) {} - uint8_t GetSideIndex() const { return _side; } + uint8_t GetSideIndex() const noexcept { return _side; } - uint8_t GetCreatureIndex() const { return _creature; } + uint8_t GetCreatureIndex() const noexcept { return _creature; } - bool operator==(const CreatureIndex& rhs) const { return (_side == rhs._side) && (_creature == rhs._creature); } + bool operator==(const CreatureIndex& rhs) const noexcept { + return (_side == rhs._side) && (_creature == rhs._creature); + } - bool operator!=(const CreatureIndex& rhs) const { return !operator==(rhs); } + bool operator!=(const CreatureIndex& rhs) const noexcept { return !operator==(rhs); } }; } diff --git a/src/Battling/Models/CreatureParty.hpp b/src/Battling/Models/CreatureParty.hpp index 5982085..7503148 100644 --- a/src/Battling/Models/CreatureParty.hpp +++ b/src/Battling/Models/CreatureParty.hpp @@ -9,25 +9,25 @@ namespace CreatureLib::Battling { Arbutils::Collections::List _party; public: - CreatureParty(size_t size) : _party(size) {} - CreatureParty(Arbutils::Collections::List party) : _party(party) {} - CreatureParty(std::initializer_list party) : _party(party) {} + CreatureParty(size_t size) noexcept : _party(size) {} + CreatureParty(Arbutils::Collections::List party) noexcept : _party(party) {} + CreatureParty(std::initializer_list party) noexcept : _party(party) {} - virtual ~CreatureParty() { + virtual ~CreatureParty() noexcept { for (auto c : _party) { delete c; } } - Creature* GetAtIndex(size_t index) const { return _party[index]; } + Creature* GetAtIndex(size_t index) const noexcept { return _party[index]; } - void Switch(size_t a, size_t b) { + void Switch(size_t a, size_t b) noexcept { auto ca = _party[a]; _party[a] = _party[b]; _party[b] = ca; } - bool HasAvailableCreatures() const { + bool HasAvailableCreatures() const noexcept { for (Creature* c : _party) { if (c == nullptr) continue; @@ -38,10 +38,10 @@ namespace CreatureLib::Battling { return false; } - Arbutils::Collections::List& GetParty() { return _party; } - const Arbutils::Collections::List& GetParty() const { return _party; } + Arbutils::Collections::List& GetParty() noexcept { return _party; } + const Arbutils::Collections::List& GetParty() const noexcept { return _party; } - size_t GetLength() const { return _party.Count(); } + size_t GetLength() const noexcept { return _party.Count(); } }; } diff --git a/src/Battling/ScriptHandling/ScriptSet.hpp b/src/Battling/ScriptHandling/ScriptSet.hpp index c0f9aa9..dbd331f 100644 --- a/src/Battling/ScriptHandling/ScriptSet.hpp +++ b/src/Battling/ScriptHandling/ScriptSet.hpp @@ -8,7 +8,7 @@ namespace CreatureLib::Battling { class ScriptSet { Arbutils::Collections::List _scripts; - std::unordered_map _lookup; + Arbutils::Collections::Dictionary _lookup; public: ~ScriptSet() { @@ -18,22 +18,23 @@ namespace CreatureLib::Battling { } void Add(Script* script) { - auto f = _lookup.find(script->GetName()); - if (f != _lookup.end()) { - _scripts[f.operator*().second]->Stack(); + size_t v; + if (_lookup.TryGet(script->GetName(), v)) { + _scripts[v]->Stack(); delete script; return; } + _scripts.Append(script); - _lookup.insert({script->GetName(), _scripts.Count() - 1}); + _lookup.Insert(script->GetName(), _scripts.Count() - 1); } Script* Get(const ConstString& key) const { return Get(key.GetHash()); } - Script* Get(uint32_t keyHash) const { - auto f = _lookup.find(keyHash); - if (f != _lookup.end()) { - return _scripts[f->second]; + Script* Get(uint32_t keyHash) const noexcept { + size_t v; + if (_lookup.TryGet(keyHash, v)) { + return _scripts[v]; } return nullptr; } @@ -41,27 +42,28 @@ namespace CreatureLib::Battling { void Remove(const ConstString& key) { Remove(key.GetHash()); } void Remove(uint32_t keyHash) { - auto find = _lookup.find(keyHash); - if (find != _lookup.end()) { - auto script = _scripts[find->second]; + size_t v; + if (_lookup.TryGet(keyHash, v)) { + auto script = _scripts[v]; script->OnRemove(); delete script; - _scripts.Remove(find.operator*().second); - _lookup.erase(keyHash); + _scripts.Remove(v); + _lookup.Remove(keyHash); } } void Clear() { for (auto s : _scripts) { + s->OnRemove(); delete s; } _scripts.Clear(); - _lookup.clear(); + _lookup.Clear(); } - bool Has(const ConstString& key) const { return _lookup.find(key) != _lookup.end(); } + bool Has(const ConstString& key) const { return _lookup.Has(key); } - bool Has(uint32_t keyHash) const { return _lookup.find(keyHash) != _lookup.end(); } + bool Has(uint32_t keyHash) const { return _lookup.Has(keyHash); } size_t Count() const { return _scripts.Count(); } diff --git a/src/Battling/TurnChoices/AttackTurnChoice.hpp b/src/Battling/TurnChoices/AttackTurnChoice.hpp index dd9ce1e..6e0442a 100644 --- a/src/Battling/TurnChoices/AttackTurnChoice.hpp +++ b/src/Battling/TurnChoices/AttackTurnChoice.hpp @@ -32,21 +32,21 @@ namespace CreatureLib::Battling { AssertNotNull(attack) ResolveScript(); } - AttackTurnChoice(Creature* user, LearnedAttack* attack, const CreatureIndex& target, Script* script) + AttackTurnChoice(Creature* user, LearnedAttack* attack, const CreatureIndex& target, Script* script) noexcept : BaseTurnChoice(user), _attack(attack), _target(target), _attackScript(script) {} - inline LearnedAttack* GetAttack() const { return _attack; } + inline LearnedAttack* GetAttack() const noexcept { return _attack; } - TurnChoiceKind GetKind() const override { return TurnChoiceKind ::Attack; } + TurnChoiceKind GetKind() const noexcept override { return TurnChoiceKind ::Attack; } int8_t GetPriority() const { // HOOK: Change priority return _attack->GetAttack()->GetPriority(); } - const CreatureIndex& GetTarget() const { return _target; } + const CreatureIndex& GetTarget() const noexcept { return _target; } - Script* GetAttackScript() const { return _attackScript; } + Script* GetAttackScript() const noexcept { return _attackScript; } protected: void GetActiveScripts(Arbutils::Collections::List& scripts) override { diff --git a/src/Battling/TurnChoices/BaseTurnChoice.hpp b/src/Battling/TurnChoices/BaseTurnChoice.hpp index 347ced5..697e65d 100644 --- a/src/Battling/TurnChoices/BaseTurnChoice.hpp +++ b/src/Battling/TurnChoices/BaseTurnChoice.hpp @@ -12,12 +12,12 @@ namespace CreatureLib::Battling { Creature* _user; protected: - BaseTurnChoice(Creature* user) : _user(user){}; + BaseTurnChoice(Creature* user) noexcept : _user(user){}; public: virtual ~BaseTurnChoice() = default; - [[nodiscard]] virtual TurnChoiceKind GetKind() const = 0; - [[nodiscard]] inline Creature* GetUser() const { return _user; } + [[nodiscard]] virtual TurnChoiceKind GetKind() const noexcept = 0; + [[nodiscard]] inline Creature* GetUser() const noexcept { return _user; } }; } diff --git a/src/Battling/TurnChoices/FleeTurnChoice.hpp b/src/Battling/TurnChoices/FleeTurnChoice.hpp index 7f975c7..076ea5a 100644 --- a/src/Battling/TurnChoices/FleeTurnChoice.hpp +++ b/src/Battling/TurnChoices/FleeTurnChoice.hpp @@ -9,7 +9,7 @@ namespace CreatureLib::Battling { public: FleeTurnChoice(Creature* user) : BaseTurnChoice(user) {} - TurnChoiceKind GetKind() const override { return TurnChoiceKind ::Flee; } + TurnChoiceKind GetKind() const noexcept override { return TurnChoiceKind ::Flee; } protected: void GetActiveScripts(Arbutils::Collections::List& scripts) override { diff --git a/src/Battling/TurnChoices/PassTurnChoice.hpp b/src/Battling/TurnChoices/PassTurnChoice.hpp index a8cceb9..f762f50 100644 --- a/src/Battling/TurnChoices/PassTurnChoice.hpp +++ b/src/Battling/TurnChoices/PassTurnChoice.hpp @@ -8,7 +8,7 @@ namespace CreatureLib::Battling { public: PassTurnChoice(Creature* c) : BaseTurnChoice(c) {} - TurnChoiceKind GetKind() const override { return TurnChoiceKind ::Pass; } + TurnChoiceKind GetKind() const noexcept override { return TurnChoiceKind ::Pass; } protected: void GetActiveScripts(Arbutils::Collections::List& scripts) override { diff --git a/src/Battling/TurnChoices/SwitchTurnChoice.hpp b/src/Battling/TurnChoices/SwitchTurnChoice.hpp index 2203edf..2da647e 100644 --- a/src/Battling/TurnChoices/SwitchTurnChoice.hpp +++ b/src/Battling/TurnChoices/SwitchTurnChoice.hpp @@ -7,13 +7,12 @@ namespace CreatureLib::Battling { Creature* _newCreature; public: - SwitchTurnChoice(Creature* user, Creature* newCreature) : BaseTurnChoice(user), _newCreature(newCreature) { - AssertNotNull(_newCreature) - } + SwitchTurnChoice(Creature* user, Creature* newCreature) noexcept + : BaseTurnChoice(user), _newCreature(newCreature) {} - TurnChoiceKind GetKind() const final { return TurnChoiceKind::Switch; } + TurnChoiceKind GetKind() const noexcept final { return TurnChoiceKind::Switch; } - inline Creature* GetNewCreature() const { return _newCreature; } + inline Creature* GetNewCreature() const noexcept { return _newCreature; } protected: void GetActiveScripts(Arbutils::Collections::List& scripts) override { diff --git a/src/Library/Attacks/AttackData.cpp b/src/Library/Attacks/AttackData.cpp index 5b7dac7..9749096 100644 --- a/src/Library/Attacks/AttackData.cpp +++ b/src/Library/Attacks/AttackData.cpp @@ -9,9 +9,9 @@ CreatureLib::Library::AttackData::AttackData(const ConstString& name, uint8_t ty : _name(std::move(name)), _type(type), _category(category), _basePower(power), _accuracy(accuracy), _baseUsages(baseUsage), _target(target), _priority(priority), _flags(std::move(flags)) {} -bool CreatureLib::Library::AttackData::HasFlag(const ConstString& key) const { +bool CreatureLib::Library::AttackData::HasFlag(const ConstString& key) const noexcept { return this->_flags.find(key) != this->_flags.end(); } -bool CreatureLib::Library::AttackData::HasFlag(uint32_t key) const { +bool CreatureLib::Library::AttackData::HasFlag(uint32_t key) const noexcept { return this->_flags.find(key) != this->_flags.end(); } diff --git a/src/Library/Attacks/AttackData.hpp b/src/Library/Attacks/AttackData.hpp index 5c59182..b2f5330 100644 --- a/src/Library/Attacks/AttackData.hpp +++ b/src/Library/Attacks/AttackData.hpp @@ -27,17 +27,17 @@ namespace CreatureLib::Library { uint8_t baseUsage, AttackTarget target, int8_t priority, std::unordered_set flags); virtual ~AttackData() = default; - inline const ConstString& GetName() const { return _name; } - inline const uint8_t GetType() const { return _type; } - inline AttackCategory GetCategory() const { return _category; } - inline uint8_t GetBasePower() const { return _basePower; } - inline uint8_t GetAccuracy() const { return _accuracy; } - inline uint8_t GetBaseUsages() const { return _baseUsages; } - inline AttackTarget GetTarget() const { return _target; } - inline int8_t GetPriority() const { return _priority; } + inline const ConstString& GetName() const noexcept { return _name; } + inline const uint8_t GetType() const noexcept { return _type; } + inline AttackCategory GetCategory() const noexcept { return _category; } + inline uint8_t GetBasePower() const noexcept { return _basePower; } + inline uint8_t GetAccuracy() const noexcept { return _accuracy; } + inline uint8_t GetBaseUsages() const noexcept { return _baseUsages; } + inline AttackTarget GetTarget() const noexcept { return _target; } + inline int8_t GetPriority() const noexcept { return _priority; } - bool HasFlag(const ConstString& key) const; - bool HasFlag(uint32_t keyHash) const; + bool HasFlag(const ConstString& key) const noexcept; + bool HasFlag(uint32_t keyHash) const noexcept; }; } diff --git a/src/Library/DataLibrary.cpp b/src/Library/DataLibrary.cpp index 1958060..eefd277 100644 --- a/src/Library/DataLibrary.cpp +++ b/src/Library/DataLibrary.cpp @@ -15,24 +15,26 @@ CreatureLib::Library::DataLibrary::DataLibrary(LibrarySettings* settings, Creatu AssertNotNull(_typeLibrary) } -const CreatureLib::Library::LibrarySettings* CreatureLib::Library::DataLibrary::GetSettings() const { +const CreatureLib::Library::LibrarySettings* CreatureLib::Library::DataLibrary::GetSettings() const noexcept { return _settings; } -const CreatureLib::Library::SpeciesLibrary* CreatureLib::Library::DataLibrary::GetSpeciesLibrary() const { +const CreatureLib::Library::SpeciesLibrary* CreatureLib::Library::DataLibrary::GetSpeciesLibrary() const noexcept { return _species; } -const CreatureLib::Library::AttackLibrary* CreatureLib::Library::DataLibrary::GetAttackLibrary() const { +const CreatureLib::Library::AttackLibrary* CreatureLib::Library::DataLibrary::GetAttackLibrary() const noexcept { return _attacks; } -const CreatureLib::Library::ItemLibrary* CreatureLib::Library::DataLibrary::GetItemLibrary() const { return _items; } +const CreatureLib::Library::ItemLibrary* CreatureLib::Library::DataLibrary::GetItemLibrary() const noexcept { + return _items; +} -const CreatureLib::Library::GrowthRateLibrary* CreatureLib::Library::DataLibrary::GetGrowthRates() const { +const CreatureLib::Library::GrowthRateLibrary* CreatureLib::Library::DataLibrary::GetGrowthRates() const noexcept { return _growthRates; } -const CreatureLib::Library::TypeLibrary* CreatureLib::Library::DataLibrary::GetTypeLibrary() const { +const CreatureLib::Library::TypeLibrary* CreatureLib::Library::DataLibrary::GetTypeLibrary() const noexcept { return _typeLibrary; } diff --git a/src/Library/DataLibrary.hpp b/src/Library/DataLibrary.hpp index a2426bd..1a2dc2b 100644 --- a/src/Library/DataLibrary.hpp +++ b/src/Library/DataLibrary.hpp @@ -34,12 +34,12 @@ namespace CreatureLib::Library { delete _typeLibrary; } - [[nodiscard]] const LibrarySettings* GetSettings() const; - [[nodiscard]] const SpeciesLibrary* GetSpeciesLibrary() const; - [[nodiscard]] const AttackLibrary* GetAttackLibrary() const; - [[nodiscard]] const ItemLibrary* GetItemLibrary() const; - [[nodiscard]] const GrowthRateLibrary* GetGrowthRates() const; - [[nodiscard]] const TypeLibrary* GetTypeLibrary() const; + [[nodiscard]] const LibrarySettings* GetSettings() const noexcept; + [[nodiscard]] const SpeciesLibrary* GetSpeciesLibrary() const noexcept; + [[nodiscard]] const AttackLibrary* GetAttackLibrary() const noexcept; + [[nodiscard]] const ItemLibrary* GetItemLibrary() const noexcept; + [[nodiscard]] const GrowthRateLibrary* GetGrowthRates() const noexcept; + [[nodiscard]] const TypeLibrary* GetTypeLibrary() const noexcept; }; } diff --git a/src/Library/Items/Item.cpp b/src/Library/Items/Item.cpp index 13e7936..f8786eb 100644 --- a/src/Library/Items/Item.cpp +++ b/src/Library/Items/Item.cpp @@ -1,9 +1,11 @@ #include "Item.hpp" -bool CreatureLib::Library::Item::HasFlag(const Arbutils::CaseInsensitiveConstString& flag) const { +bool CreatureLib::Library::Item::HasFlag(const Arbutils::CaseInsensitiveConstString& flag) const noexcept { + return this->_flags.find(flag) != this->_flags.end(); +} +bool CreatureLib::Library::Item::HasFlag(uint32_t flag) const noexcept { return this->_flags.find(flag) != this->_flags.end(); } -bool CreatureLib::Library::Item::HasFlag(uint32_t flag) const { return this->_flags.find(flag) != this->_flags.end(); } CreatureLib::Library::Item::Item(const Arbutils::CaseInsensitiveConstString& name, CreatureLib::Library::ItemCategory category, diff --git a/src/Library/Items/Item.hpp b/src/Library/Items/Item.hpp index 419d25b..54166cc 100644 --- a/src/Library/Items/Item.hpp +++ b/src/Library/Items/Item.hpp @@ -20,13 +20,13 @@ namespace CreatureLib::Library { Item(const Arbutils::CaseInsensitiveConstString& name, ItemCategory category, BattleItemCategory battleCategory, int32_t price, std::unordered_set flags); - inline const Arbutils::CaseInsensitiveConstString& GetName() const { return _name; } - inline ItemCategory GetCategory() const { return _category; } - inline BattleItemCategory GetBattleCategory() const { return _battleCategory; } - inline const int32_t GetPrice() const { return _price; } + inline const Arbutils::CaseInsensitiveConstString& GetName() const noexcept { return _name; } + inline ItemCategory GetCategory() const noexcept { return _category; } + inline BattleItemCategory GetBattleCategory() const noexcept { return _battleCategory; } + inline const int32_t GetPrice() const noexcept { return _price; } - bool HasFlag(const Arbutils::CaseInsensitiveConstString& flag) const; - bool HasFlag(uint32_t flag) const; + bool HasFlag(const Arbutils::CaseInsensitiveConstString& flag) const noexcept; + bool HasFlag(uint32_t flag) const noexcept; }; }