risorse | good unit tests

Good Unit Tests /12

Questa parte (la dodicesima; 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 e qui l'undicesima) descrive un piccolo refactoring.

Analizzando il codice sorgente mi sono reso conto che la classe Expression, oltre a definire la strategia di logAndEvaluate, si occupa della gestione delle espressioni unarie. Conviene separare le due responsabilità introducendo una nuova classe, UnaryExpression:

// file gut.h
// ...

struct Expression {
  static std::string last;
  virtual ~Expression() { }
  virtual bool evaluate() const = 0;
  virtual std::string toString() const = 0;
  template <typename T>
  static bool logAndEvaluate(const T& value) {
    if (HasOperatorString<T>::value)
      Expression::last = StringRepr<T, HasOperatorString<T>::value>(value).str();
    else
      Expression::last = gut::toString(static_cast<bool>(value));
    return static_cast<bool>(value);
  }
  bool logAndEvaluate() {
    Expression::last = toString();
    return evaluate();
  }
};

std::string Expression::last;

template<typename T>
class UnaryExpression : public Expression {
protected:
  const T& value_;
public:
  UnaryExpression(const T& value) : value_(value) { }
  virtual bool evaluate() const {
    return static_cast<bool>(value_);
  }
  virtual std::string toString() const {
    if (HasOperatorString<T>::value)
      return StringRepr<T, HasOperatorString<T>::value>(value_).str();
    else
      return gut::toString(static_cast<bool>(value_));
  }
};

// ...

template<typename T>
class Term {
  // ...

  operator bool() const {
    return Expression::logAndEvaluate(lhs_);
    return UnaryExpression<T>(lhs_).logAndEvaluate();
  }
  // ...

};

Codice sorgente

Pagina modificata il 07/10/2014