1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <functional>
6
7#include <lib/fit/function.h>
8#include <lib/fit/function_traits.h>
9#include <unittest/unittest.h>
10
11namespace {
12
13template <typename Callable, typename... Args>
14void invoke_with_defaults(Callable c, fit::parameter_pack<Args...>) {
15    c(Args()...);
16}
17
18template <typename Callable>
19void invoke_with_defaults(Callable c) {
20    invoke_with_defaults(std::move(c), typename fit::function_traits<Callable>::args{});
21}
22
23bool arg_capture() {
24    BEGIN_TEST;
25
26    int i = 0;
27    invoke_with_defaults([&] { i = 42; });
28    EXPECT_EQ(42, i);
29    invoke_with_defaults([&](int, float) { i = 54; });
30    EXPECT_EQ(54, i);
31
32    END_TEST;
33}
34
35// Performs static assertions against a function-like type of signature int(float, bool).
36template <typename Callable>
37struct TraitsTest {
38    using Traits = fit::function_traits<Callable>;
39
40    static_assert(std::is_same_v<int(float, bool), typename Traits::signature>);
41    static_assert(std::is_same_v<int, typename Traits::return_type>);
42    static_assert(2 == Traits::args::size);
43    static_assert(std::is_same_v<float, typename Traits::args::template at<0>>);
44    static_assert(std::is_same_v<bool, typename Traits::args::template at<1>>);
45};
46
47// compile-time test
48namespace signature_traits {
49    using Traits = TraitsTest<int(float, bool)>::Traits;
50} // namespace signature_traits
51
52// compile-time test
53namespace function_pointer_traits {
54    using Traits = TraitsTest<int (*)(float, bool)>::Traits;
55    static_assert(std::is_same_v<int (*)(float, bool), Traits::type>);
56} // namespace function_pointer_traits
57
58// compile-time test
59namespace lambda_traits {
60    auto lambda = [](float, bool) { return 0; };
61    using Traits = TraitsTest<decltype(lambda)>::Traits;
62} // namespace lambda_traits
63
64template <typename Functor>
65struct FunctorTraitsTest {
66    using Traits = typename TraitsTest<Functor>::Traits;
67    static_assert(std::is_same_v<Functor, typename Traits::type>);
68};
69
70// compile-time test
71namespace mutable_functor_traits {
72    struct MutableFunctor {
73        int operator()(float, bool) { return 0; }
74    };
75    using Traits = FunctorTraitsTest<MutableFunctor>::Traits;
76} //namespace mutable_functor_traits
77
78// compile-time test
79namespace fit_function_traits {
80    using Traits = FunctorTraitsTest<fit::function<int(float, bool)>>;
81} // namespace fit_function_traits
82
83// compile-time test
84namespace std_function_traits {
85    using Traits = FunctorTraitsTest<std::function<int(float, bool)>>;
86} // namespace std_function_traits
87
88} // namespace
89
90BEGIN_TEST_CASE(function_traits_tests)
91RUN_TEST(arg_capture)
92// suppress -Wunneeded-internal-declaration
93(void)lambda_traits::lambda;
94END_TEST_CASE(function_traits_tests)
95