risorse | good unit tests
Questa parte (la quindicesima; qui la prima, qui la seconda, qui la terza, qui la quarta, qui la quinta, qui la sesta, qui la settima, qui l'ottava, qui la nona, qui la decima, qui l'undicesima, qui la dodicesima, qui la tredicesima e qui la quattordicesima) risolve un problema relativo alla modalità GUT_ENABLE_FAILFAST e introduce il supporto dei colori nella finestra del terminale di Linux – Ubuntu 14.04 Desktop.
Durante la rifattorizzazione che ha originato le classi Listener/Report ha introdotto un problema piuttosto grave: abilitando l'opzione fail-fast, la test suite termina sì al primo errore, ma con successo. Il codice va così modificato:
class Listener { // ... void quit(const std::string& reason) {report_->quit(reason); }++failedTestCount_; report_->quit(reason); } // ... };
La finestra del terminale di Linux supporta le sequenze ANSI[2], ed è perciò sufficiente emettere i codici escape opportuni per cambiare il colore del testo. Trattandosi di fatto di caratteri extra che potrebbero rendere più difficoltoso un eventuale parsing del prospetto prodotto dall'oggetto Report, conviene rendere opzionale la loro presenza. L'implementazione del controllo può avvenire con la stessa modalità con cui è stato realizzato il flag GUT_ENABLE_FAILFAST:
namespace gut { // static flag, initially reset; declare an instance to set it template<class T> class StaticFlag { static bool flag_; public: StaticFlag() { flag_ = true; } static bool enabled() { return flag_; } }; // enable/disable colors in console template<class T> bool StaticFlag<T>::flag_ = false; namespace color { struct ColorInConsole_ { }; typedef StaticFlag<ColorInConsole_> ColorInConsole; #define GUT_ENABLE_COLORINCONSOLE gut::color::ColorInConsole colorInConsole_; } // namespace color } // namespace gut#include "colors.h"#ifdef _WIN32 #include "windows/colors.h" #else #include "linux/colors.h" #endif // ...class FailFast { static bool enabled_; public: FailFast() { enabled_ = true; } static bool enabled() { return enabled_; } }; bool FailFast::enabled_ = false;struct FailFast_ { }; typedef StaticFlag<FailFast_> FailFast;
L'implementazione dei due flag ColorInConsole e FailFast per mezzo di una classe generica comune e un tipo ausiliario vuoto che consente l'istanziazione differenziata del membro statico è nota come tag dispatching[1][3].
Il supporto del testo colorato in Linux è banale:
// file linux/colors.h #ifndef COLORS_H #define COLORS_H namespace gut { namespace color { std::ostream& setForegroundColor(std::ostream& os, const char* code) { if (ColorInConsole::enabled()) os << "\x1b[" << code << "m"; return os; } std::ostream& black(std::ostream& os) { return setForegroundColor(os, "30"); } std::ostream& navy(std::ostream& os) { return setForegroundColor(os, "34"); } std::ostream& green(std::ostream& os) { return setForegroundColor(os, "32"); } std::ostream& teal(std::ostream& os) { return setForegroundColor(os, "36"); } std::ostream& maroon(std::ostream& os) { return setForegroundColor(os, "31"); } std::ostream& purple(std::ostream& os) { return setForegroundColor(os, "35"); } std::ostream& olive(std::ostream& os) { return setForegroundColor(os, "33"); } std::ostream& silver(std::ostream& os) { return setForegroundColor(os, "37"); } std::ostream& gray(std::ostream& os) { return setForegroundColor(os, "90"); } std::ostream& blue(std::ostream& os) { return setForegroundColor(os, "94"); } std::ostream& lime(std::ostream& os) { return setForegroundColor(os, "92"); } std::ostream& aqua(std::ostream& os) { return setForegroundColor(os, "96"); } std::ostream& red(std::ostream& os) { return setForegroundColor(os, "91"); } std::ostream& fuchsia(std::ostream& os) { return setForegroundColor(os, "95"); } std::ostream& yellow(std::ostream& os) { return setForegroundColor(os, "93"); } std::ostream& white(std::ostream& os) { return setForegroundColor(os, "97"); } std::ostream& reset(std::ostream& os) { return setForegroundColor(os, "0"); } } // namespace color } // namespace gut #endif // COLORS_H
Anche l'implementazione dell'oggetto Console per Windows va modificata in modo da colorare il testo solo quando richiesto:
// file windows/colors.h (was: colors.h) // ... namespace gut { namespace color { class WindowsConsole_ { HANDLE handle_; WORD defaultAttrs_; static const WORD mask_ = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY; public: WindowsConsole_() : handle_(GetStdHandle(STD_OUTPUT_HANDLE)) , defaultAttrs_(getAttrs()) { } void setColor(WORD color) { if (ColorInConsole::enabled()) SetConsoleTextAttribute(handle_, (getAttrs() & ~mask_) | color); } void resetColors() { if (ColorInConsole::enabled()) SetConsoleTextAttribute(handle_, defaultAttrs_); } protected: WORD getAttrs() { CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(handle_, &info); return info.wAttributes; } }; WindowsConsole_& theConsole() { static WindowsConsole_ console; return console; } // ... } // namespace color } // namespace gut #endif // COLORS_H
L'uso dei colori nella console è quindi normalmente disattivato; per attivarlo è necessario inserire la direttiva GUT_ENABLE_COLORINCONSOLE all'inizio della test suite:
// file example.cpp // ... GUT_ENABLE_COLORINCONSOLE TEST("Initial list is empty") { RecentlyUsedList anEmptyList; CHECK(anEmptyList.empty()); CHECK(anEmptyList.size() == 0); } // ...
Pagina modificata il 29/04/2015