(wangle) codegen then() variant tests
authorHans Fugal <fugalh@fb.com>
Mon, 7 Apr 2014 16:57:42 +0000 (09:57 -0700)
committerptarjan <ptarjan@fb.com>
Wed, 9 Apr 2014 03:59:14 +0000 (20:59 -0700)
Summary:
When all the variants I am dreaming of work, there's a little more than
100 tests generated.

Test Plan: fbmake runtests

Reviewed By: hannesr@fb.com

FB internal diff: D1258754

folly/wangle/test/Thens.cpp [new file with mode: 0644]
folly/wangle/test/Thens.h [new file with mode: 0644]
folly/wangle/test/thens.rb [new file with mode: 0755]

diff --git a/folly/wangle/test/Thens.cpp b/folly/wangle/test/Thens.cpp
new file mode 100644 (file)
index 0000000..633c925
--- /dev/null
@@ -0,0 +1,19 @@
+// This file is @generated by thens.rb
+
+#include "Thens.h"
+
+TEST(Future, thenVariants) {
+  SomeClass anObject;
+  Executor* anExecutor;
+
+  {Future<B> f = someFuture<A>().then(aFunction<Future<B>, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
+  {Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
+  {Future<B> f = someFuture<A>().then(aFunction<B, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
+  {Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
+}
diff --git a/folly/wangle/test/Thens.h b/folly/wangle/test/Thens.h
new file mode 100644 (file)
index 0000000..455f2d6
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <gtest/gtest.h>
+#include <memory>
+#include "folly/wangle/Future.h"
+#include "folly/wangle/Executor.h"
+
+using namespace folly::wangle;
+using namespace std;
+using namespace testing;
+
+typedef unique_ptr<int> A;
+struct B {};
+
+template <class T>
+using EnableIfFuture = typename std::enable_if<isFuture<T>::value>::type;
+
+template <class T>
+using EnableUnlessFuture = typename std::enable_if<!isFuture<T>::value>::type;
+
+template <class T>
+Future<T> someFuture() {
+  return makeFuture(T());
+}
+
+template <class Ret, class... Params, typename = void>
+Ret aFunction(Params...);
+
+template <class Ret, class... Params>
+typename std::enable_if<isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+  typedef typename Ret::value_type T;
+  return makeFuture(T());
+}
+
+template <class Ret, class... Params>
+typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+  return Ret();
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(typename std::enable_if<!isFuture<Ret>::value, bool>::type = false) {
+  return [](Params...) -> Ret { return Ret(); };
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(typename std::enable_if<isFuture<Ret>::value, bool>::type = true) {
+  typedef typename Ret::value_type T;
+  return [](Params...) -> Future<T> { return makeFuture(T()); };
+}
+
+class SomeClass {
+  B b;
+public:
+  template <class Ret, class... Params>
+  static Ret aStaticMethod(Params...);
+
+  template <class Ret, class... Params>
+  static
+  typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+  aStaticMethod(Params...) {
+    return Ret();
+  }
+
+  template <class Ret, class... Params>
+  static
+  typename std::enable_if<isFuture<Ret>::value, Ret>::type
+  aStaticMethod(Params...) {
+    typedef typename Ret::value_type T;
+    return makeFuture(T());
+  }
+
+  template <class Ret, class... Params>
+  Ret aMethod(Params...);
+
+  template <class Ret, class... Params>
+  typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+  aMethod(Params...) {
+    return Ret();
+  }
+
+  template <class Ret, class... Params>
+  typename std::enable_if<isFuture<Ret>::value, Ret>::type
+  aMethod(Params...) {
+    typedef typename Ret::value_type T;
+    return makeFuture(T());
+  }
+};
diff --git a/folly/wangle/test/thens.rb b/folly/wangle/test/thens.rb
new file mode 100755 (executable)
index 0000000..2f07353
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/env ruby
+
+# An exercise in combinatorics.
+# (ordinary/static function, member function, std::function, lambda)
+# X
+# returns (Future<R>, R)
+# X
+# accepts (Try<T>&&, Try<T> const&, Try<T>, T&&, T const&, T, nothing)
+
+def test(*args)
+  args = args.join(", ")
+  [
+  "{Future<B> f = someFuture<A>().then(#{args});}",
+  #"{Future<B> f = makeFuture(A()).then(#{args}, anExecutor);}",
+  ]
+end
+
+def retval(ret)
+  {
+    "Future<B>" => "someFuture<B>()",
+    "Try<B>" => "Try<B>(B())",
+    "B" => "B()"
+  }[ret]
+end
+
+return_types = [
+  "Future<B>",
+  "B",
+  #"Try<B>",
+]
+param_types = [
+    "Try<A>&&",
+    #"Try<A> const&",
+    #"Try<A>",
+    #"Try<A>&",
+    #"A&&",
+    #"A const&",
+    #"A",
+    #"A&",
+    #"",
+  ]
+
+tests = (
+  return_types.map { |ret|
+    param_types.map { |param|
+      both = "#{ret}, #{param}"
+      [
+        ["aFunction<#{both}>"],
+        ["&SomeClass::aStaticMethod<#{both}>"],
+        # TODO switch these around (std::bind-style)
+        ["&anObject", "&SomeClass::aMethod<#{both}>"],
+        ["aStdFunction<#{both}>()"],
+        ["[&](#{param}){return #{retval(ret)};}"],
+      ]
+    }
+  }.flatten(2) + [
+    #[""],
+  ]
+).map {|a| test(a)}.flatten
+
+print <<EOF
+// This file is #{"@"}generated by thens.rb
+
+#include "Thens.h"
+
+TEST(Future, thenVariants) {
+  SomeClass anObject;
+  Executor* anExecutor;
+
+  #{tests.join("\n  ")}
+}
+EOF