risorse | good unit tests

Good Unit Tests /9

Questa breve parte (la nona; qui la prima, qui la seconda, qui la terza, qui la quarta, qui la quinta, qui la sesta, qui la settima e qui l'ottava) è dedicata al supporto dell'oggetto nullptr.

Supporto di nullptr

L'infrastruttura non consente ancora il confronto tra puntatori e nullptr:

  ...

  CHECK(&obj == nullptr); // does not compile!
  ...

Per abilitare questo tipo di comparazioni è sufficiente specializzare l'espressione binaria, nelle due varianti – nullptr a destra e a sinitra:

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

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

Poiché non è possibile serializzare l'oggetto nullptr in uno stream, è necessario prevedere un operatore di conversione a stringa:

std::string toString(std::nullptr_t) {
  return "<nullptr>";
}

Il programma di test diventa:

  ...
  CHECK(NULL == cpi1);
  //~ assert(lastFailure == "[error] NULL == cpi1 evaluates to 0 == 0012FF24");

  // nullptr
  CHECK(pi1 == nullptr);
  //~ assert(lastFailure == "[error] pi1 == nullptr evaluates to 0012FF24 == <nullptr>");

  CHECK(&i1 == nullptr);
  //~ assert(lastFailure == "[error] &i1 == nullptr evaluates to 0012FF24 == <nullptr>");

  int* pnullptr = nullptr;

  CHECK(pnullptr != NULL);
  //~ assert(lastFailure == "[error] pnullptr != NULL evaluates to 00000000 != 00000000");

  CHECK(pnullptr != 0);
  //~ assert(lastFailure == "[error] pnullptr != 0 evaluates to 00000000 != 00000000");

  CHECK(cpi1 == nullptr);
  //~ assert(lastFailure == "[error] cpi1 == nullptr evaluates to 0012FF24 == <nullptr>");

  CHECK(nullptr == &i1);
  //~ assert(lastFailure == "[error] nullptr == &i1 evaluates to <nullptr> == 0012FF24");

  CHECK(0 != pnullptr);
  //~ assert(lastFailure == "[error] 0 != pnullptr evaluates to 00000000 != 00000000");

  CHECK(NULL != pnullptr);
  //~ assert(lastFailure == "[error] NULL != pnullptr evaluates to 00000000 != 00000000");

  CHECK(nullptr == cpi1);
  //~ assert(lastFailure == "[error] nullptr == cpi1 evaluates to <nullptr> == 0012FF24");

  // objects
  Object o1(1);
  Object o2(2);
  ...

Al solito, trattandosi di puntatori, le assert sono commentate, perché i valori da essi assunti non sono stabili e la loro rappresentazione dipende dal compilatore.

Aggiornamento [05/02/2014]: sempre a proposito di puntatori, la versione 4.8.2 di MinGW emette il warning «ISO C++ forbids comparison between pointer and integer» in corrispondenza dei confronti tra puntatori e costante NULL; sebbene l'uso di tale costante sia deprecata, per eliminare il messaggio basta fornire un'ulteriore specializzazione del metodo compare:

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

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

Codice sorgente

Pagina modificata il 04/02/2014