risorse | good unit tests

Good Unit Tests /16

Questa parte (la sedicesima; 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, qui la quattordicesima e qui la quindicesima) risolve alcuni piccoli problemi riscontrati nell'uso della libreria con Visual Studio Express 2013, GCC 5.1 e Clang 3.6.

Fix di DefaultReport

È stata aggiunta l'inizializzazione del membro testAlreadyFailed_ dell'oggetto DefaultReport:

class DefaultReport {
  std::ostream& os_;
  bool testAlreadyFailed_;
  std::vector<std::pair<int, std::string>> log_;
public:
  DefaultReport(std::ostream& os = std::cout)
   : os_(os), testAlreadyFailed_(false) {}
  ...
};

Operatori di assegnamento

Sono stati esplicitamente disattivati gli operatori di assegnamento delle classi non copiabili:

...
struct Expression {
  ...
  virtual ~Expression() {}
  Expression& operator=(const Expression&) = delete;
  ...
};

...
template <typename T>
class UnaryExpression : public Expression {
  ...
  UnaryExpression(const T& value) : value_(value) {}
  UnaryExpression& operator=(const UnaryExpression&) = delete;
  ...
};

...
template <typename T, typename U>
class BinaryExpression : public Expression {
  ...
  BinaryExpression(const T& lhs, const U& rhs) : lhs_(lhs), rhs_(rhs) {}
  BinaryExpression& operator=(const BinaryExpression&) = delete;
  ...
};

...
template <typename T>
class Term {
  ...
  Term& operator=(const Term&) = delete;
  template <typename U>
  UNEXPECTED_ASSIGNMENT operator=(const U&) const;
  ...
};

...
class DefaultReport {
  ...
public:
  ...
  DefaultReport& operator=(const DefaultReport&) = delete;
  void start() { os_ << "Test suite started..." << std::endl; }
  ...
};

La costante NULL e 64 bit

È stato aggiunto il supporto per il confronto dei puntatori con NULL per i sistemi nei quali la costante è un long (tipicamente negli ambienti a 64 bit):

...
template <Operator op, typename T>
bool compare(T* lhs, long rhs) {
  return ExprFactory<T*, T*, op>::logAndEvaluate(
    lhs, reinterpret_cast<T*>(rhs));
}

template <Operator op, typename T>
bool compare(long lhs, T* rhs) {
  return ExprFactory<T*, T*, op>::logAndEvaluate(
    reinterpret_cast<T*>(lhs), rhs);
}

Errore “incomplete type OPERATION_NOT_SUPPORTED”

Durante la compilazione dei programmi d'esempio, Clang 3.6 genera l'errore in oggetto; per eliminarlo senza rinunciare all'hint dato dalla presenza del nome nel messaggio d'errore, si è uniformata la forma del metodo logAndEvaluate a quello degli operatori della classe Term:

...
struct ExprFactory {
  static bool logAndEvaluate(const T& /*lhs*/, const U& /*rhs*/) {
    OPERATION_NOT_SUPPORTED dummy;
    return false;
  }
  static OPERATION_NOT_SUPPORTED logAndEvaluate(const T&, const U&);
};

Confronto int/unsigned long long

È stato aggiunto un esplicito operatore di confronto tra i due tipi interi in oggetto, per evitare l'emissione di un warning relativo a comparazioni tra valori numerici signed/unsigned:

...
template <Operator op>
bool compare(int lhs, unsigned long long rhs) {
  return compare<op>(static_cast<unsigned long long>(lhs), rhs);
}

template <Operator op>
bool compare(unsigned long long lhs, int rhs) {
  return compare<op>(lhs, static_cast<unsigned long long>(rhs));
}

Ridenominazione delle macro ausiliarie

È stato aggiunto il prefisso GUT_ a tutte le macro di supporto, per ridurre le probabilità clashing:

...
#define GUT_INT_BASE Dec
#define GUT_CHAR_BASE Hex

#define CONCAT GUT_CONCAT_(a, b) a ## b
#define CONCAT_ GUT_CONCAT(a, b) CONCAT GUT_CONCAT_(a, b)

#define GUT_INT_TO_STRING  CONCAT_ GUT_CONCAT(as, GUT_INT_BASE)
#define GUT_CHAR_TO_STRING CONCAT_ GUT_CONCAT(as, GUT_CHAR_BASE)

...
#define GUT_PICK_NAME(id_) e_ ## id_,
#define GUT_PICK_LABEL(id_) #id_,

#define GUT_LEVELS(lambda_) \
  lambda_(info) \
  lambda_(warning) \
  lambda_(error) \
  lambda_(fatal) \

enum Level { GUT_LEVELS(GUT_PICK_NAME) };
static std::string level_name[] = { GUT_LEVELS(GUT_PICK_LABEL) };

...
#define MAKE_UNIQUE(name_) CONCAT_(name_, __LINE__)
#define GUT_ID(prefix_) GUT_CONCAT(prefix_, __LINE__)

#define TEST(name_) \
  static void MAKE_UNIQUE GUT_ID(test_)(); \
  gut::Suite::add MAKE_UNIQUE GUT_ID(testAddition_)(
    name_, &CONCAT_ GUT_CONCAT(test_, __LINE__)); \
  static void MAKE_UNIQUE GUT_ID(test_)()

Warning “conditional expression is constant”

Il Visual Studio Express 2013 emette alcuni warning C4127 spurii quando compila il sorgente al livello di warning 4 (/W4); i messaggi possono essere inibiti puntualmente con un'istruzione pragma:

template <typename T>
class UnaryExpression : public Expression {
  ...
  virtual std::string toString() const {
#ifdef _MSC_VER
__pragma(warning(push))
__pragma(warning(disable:4127))
#endif
    if (HasOperatorString<T>::value)
#ifdef _MSC_VER
__pragma(warning(pop))
#endif
      return StringRepr<T, HasOperatorString<T>::value>(value_).str();
    else
      return gut::toString(static_cast<bool>(value_));
  }
};

...
#define GUT_BEGIN \
    do {

#ifdef _MSC_VER

#define GUT_END \
__pragma(pack(push)) \
__pragma(warning(disable:4127)) \
    } while (0) \
__pragma(pack(pop))

#else

#define GUT_END \
    } while (0)

#endif

Il costrutto do/while che caratterizza le macro di test è stato sostituito dall'accoppiata GUT_BEGIN/GUT_END; a titolo d'esempio, la macro CHECK diventa:

#define CHECK(expr_) \
  GUT_BEGIN do { \
    if (!(gut::Capture()->*expr_)) \
      gut::theListener.failure(
        gut::CheckFailure(
          #expr_, gut::Expression::last, __FILE__, __LINE__)); \
  GUT_END } while (0)

Codice sorgente

Pagina modificata il 04/06/2015