#!/usr/bin/env ruby

# cd folly/futures/test && ruby then_compile_test.rb > ThenCompileTest.cpp

# 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|
      if param != "" then
        both = "#{ret}, #{param}"
        [
          ["&aFunction<#{both}>"],
          ["&SomeClass::aStaticMethod<#{both}>"],
          ["&SomeClass::aMethod<#{both}>", "&anObject"],
          ["aStdFunction<#{both}>()"],
          ["[&](#{param}){return #{retval(ret)};}"],
        ]
      else
        [["[&](){return #{retval(ret)};}"]]
      end
    }
  }.flatten(2)
).map {|a| test(a)}.flatten

print <<EOF
// This file is #{"@"}generated by then_compile_test.rb. Do not edit directly.

#include <folly/futures/test/ThenCompileTest.h>

using namespace folly;

TEST(Basic, thenVariants) {
  SomeClass anObject;

  #{tests.join("\n  ")}
}
EOF
