Ver código fonte

Add the ability to implement contracts on a return-value.

A better way to implement this would be to implement the contract not as a capture but instead as a forwarding device.
Sam Jaffe 5 anos atrás
pai
commit
1d4f5d6556
2 arquivos alterados com 48 adições e 1 exclusões
  1. 38 1
      include/expect/expect.hpp
  2. 10 0
      test/expect_test.cxx

+ 38 - 1
include/expect/expect.hpp

@@ -115,7 +115,6 @@ namespace contract {
                DEF_MSG("postcondition", FIRST(__VA_ARGS__))) \
   )
 
-
 /**
  * RVO works if expr is an rvalue, but not if it is an
  * lvalue. e.g:
@@ -155,3 +154,41 @@ namespace contract {
     return _; \
   }( )
 #endif
+
+namespace contract {
+  template <typename T>
+  struct postcondition_helper {
+    void(*deleter)(T const*);
+    T const* object;
+    
+    postcondition_helper() = default;
+    postcondition_helper(postcondition_helper &&) = delete;
+    postcondition_helper(postcondition_helper const&) = delete;
+    ~postcondition_helper() { if (deleter) deleter(object); }
+    
+    T const & operator=(T const & rhs) {
+      object = &rhs;
+      deleter = [](void const*) {};
+      return rhs;
+    }
+    
+    T const & operator=(T && rhs) {
+      object = new T(rhs);
+      deleter = [](T const* ptr) { delete ptr; };
+      return *object;
+    }
+    
+    T const * operator->() const { return object; }
+    
+    bool operator==(T const & rhs) const { return *object == rhs; }
+    bool operator!=(T const & rhs) const { return *object != rhs; }
+    bool operator<=(T const & rhs) const { return *object <= rhs; }
+    bool operator< (T const & rhs) const { return *object <  rhs; }
+    bool operator>=(T const & rhs) const { return *object >= rhs; }
+    bool operator> (T const & rhs) const { return *object >  rhs; }
+  };
+}
+
+#define contract_postconditions(type) \
+  contract::postcondition_helper<type> $return
+#define contract_return( ... ) return ($return = __VA_ARGS__)

+ 10 - 0
test/expect_test.cxx

@@ -78,6 +78,16 @@ TEST(EnsureTest, ThrowsIfFailed) {
   EXPECT_THROW(ensures(i == 6), std::runtime_error);
 }
 
+TEST(EnsureTest, CanBeMadeToCaptureRval) {
+  auto function = [](std::string const & expected) -> std::string {
+    contract_postconditions(std::string);
+    ensures($return == expected);
+    contract_return("this is a string");
+  };
+  EXPECT_THROW(function("hello world!"), std::runtime_error);
+  EXPECT_THAT(function("this is a string"), "this is a string");
+}
+
 TEST(EnsureTest, FailsWithErrorMessageContainingExpr) {
   int i = 1;
   try {