File: rust_gtest_interop.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (108 lines) | stat: -rw-r--r-- 4,704 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TESTING_RUST_GTEST_INTEROP_RUST_GTEST_INTEROP_H_
#define TESTING_RUST_GTEST_INTEROP_RUST_GTEST_INTEROP_H_

#include <stdint.h>
#include <type_traits>

namespace testing {
class Test;
}

// Macro to make an extern "C" function which acts as a Gtest factory for a
// testing::Test subclass T. Invoke this macro once for each subclass of
// testing::Test that should be used as a TestSuite class from a Rust test,
// which can be specified with `#[gtest_suite(T)]`.
//
// The function generated by the macro is used by the
// rust_gtest_interop::TestSuite trait implementation to connect a Rust test to
// the C++ class.
#define RUST_GTEST_TEST_SUITE_FACTORY(T)                              \
  extern "C" T* RustGtestFactory_##T(void (*f)(T*)) {                 \
    return rust_gtest_interop::rust_gtest_factory_for_subclass<T>(f); \
  }

namespace rust_gtest_interop {

// A simple C++ test fixture used for Rust unit tests. It provides nothing
// except the test body which calls the Rust function. The Subclass must be
// `testing::Test`, or a subclass thereof.
template <class Subclass>
class RustTest : public Subclass {
 public:
  explicit RustTest(void (&test_fn)(Subclass*)) : test_fn_(test_fn) {
    static_assert(std::is_convertible_v<Subclass*, testing::Test*>,
                  "RustTest's Subclass parameter must be a testing::Test or a "
                  "subclass of it");
  }
  void TestBody() override { test_fn_(this); }

 private:
  // Not a `raw_ref<T>` because this is a function reference.
  void (&test_fn_)(Subclass*);
};

// The TestSuite factory function which will construct a testing::Test subclass
// that runs the given function pointer as the test body. The factory function
// exists to allow choosing different subclasses of testing::Test.
using GtestFactoryFunction = testing::Test* (*)(void (*body)(testing::Test*));

// Templated implementation of GtestFactoryFunction. Rust can't use templated
// methods currently, so other fully-typed functions need to exist which can
// make use of this function, via the RUST_GTEST_TEST_SUITE_FACTORY() macro.
template <class Subclass>
Subclass* rust_gtest_factory_for_subclass(void (*body)(Subclass*)) {
  return new RustTest<Subclass>(*body);
}

// Returns a factory that will run the test function. Used for any Rust tests
// that don't need a specific C++ testing::Test subclass.
extern "C" testing::Test* rust_gtest_default_factory(
    void (*body)(testing::Test*));

// Register a test to be run via GTest. This must be called before main(), as
// there's no calls from C++ into Rust to collect tests. Any function given to
// this function will be included in the set of tests run by the RUN_ALL_TESTS()
// invocation.
//
// This function is meant to be called from Rust, for any test functions
// decorated by a #[gtest(Suite, Test)] macro, which is provided to Rust by this
// same GN target.
//
// The `test_function` signature here says it receives a `Test*`, though in fact
// the function would be specialized to receive its precise subclass of `Test*`.
// It is required that the type returned by the GtestFactoryFunction and the
// type received by the `test_function` are the same type. The type is downcast
// in Rust when the test function body is run.
//
// SAFETY: This function makes copies of the strings so the pointers do not need
// to outlive the function call.
extern "C" void rust_gtest_add_test(GtestFactoryFunction gtest_factory,
                                    void (*test_function)(testing::Test*),
                                    const char* test_suite_name,
                                    const char* test_name,
                                    const char* file,
                                    int32_t line);

// Report a test failure at a given file and line tuple, with a provided
// message.
//
// This function is meant to be called from Rust tests, via expect_eq!() and
// similar macros. It's present in a header for generating bindings from Rust.
//
// We use `unsigned char` and `int32_t` because CXX does not support
// std::os::raw::c_char or std::os::raw::c_int. See
// https://github.com/dtolnay/cxx/issues/1015.
//
// SAFETY: This function makes copies of the strings so the pointers do not need
// to outlive the function call.
extern "C" void rust_gtest_add_failure_at(const char* file,
                                          int32_t line,
                                          const char* message);

}  // namespace rust_gtest_interop

#endif  // TESTING_RUST_GTEST_INTEROP_RUST_GTEST_INTEROP_H_