blob: 4b2d72e4cd4538c348a958db26e672e0c538ac86 [file] [log] [blame]
Devin Jeanpierref643afa2022-02-23 20:50:48 +00001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5//! Test crate for `ctor_proc_macros`.
6//!
7//! Because the `ctor` crate is not visible as `::ctor` within
8//! itself, we use a separate crate for testing, which can depend on both.
9//!
10//! And because the proc macros have additional expectations on callers, this is
11//! not added to macro_test.
12
13#![cfg(test)]
14// Callers are expected to enable `negative_impls`.
Devin Jeanpierre57aac932022-05-17 17:18:44 -070015// more_qualified_paths is used to make project_pin_type!() simpler to use.
Devin Jeanpierre1c28ff22022-05-09 06:04:57 -070016#![feature(negative_impls, more_qualified_paths)]
Devin Jeanpierref643afa2022-02-23 20:50:48 +000017
18// pathological shadowed names: shadow important modules that the macros use.
19mod std {}
20mod ctor {}
21mod pin_project {}
22
23#[test]
Devin Jeanpierre31a2f972022-05-09 06:11:05 -070024fn test_derive_default_unit_struct() {
25 #[derive(::ctor::CtorFrom_Default)]
26 struct Struct;
Devin Jeanpierrea330af62022-06-09 17:03:45 -070027 unsafe impl ::ctor::RecursivelyPinned for Struct {
28 type CtorInitializedFields = Self;
29 }
Devin Jeanpierre31a2f972022-05-09 06:11:05 -070030 impl !Unpin for Struct {}
31
32 ::ctor::emplace! {let _p = <Struct as ::ctor::CtorNew<()>>::ctor_new(()); }
33}
34
35#[test]
Devin Jeanpierref643afa2022-02-23 20:50:48 +000036fn test_derive_default_struct() {
37 #[derive(::ctor::CtorFrom_Default)]
38 struct Struct {
39 x: i32,
40 y: f32,
41 }
Devin Jeanpierrea330af62022-06-09 17:03:45 -070042 unsafe impl ::ctor::RecursivelyPinned for Struct {
43 type CtorInitializedFields = Self;
44 }
Devin Jeanpierref643afa2022-02-23 20:50:48 +000045 impl !Unpin for Struct {}
46
47 ::ctor::emplace! {let p = <Struct as ::ctor::CtorNew<()>>::ctor_new(()); }
48 assert_eq!(p.x, 0);
49 assert_eq!(p.y, 0.0);
50}
51
52#[test]
53fn test_derive_default_tuple_struct() {
54 #[derive(::ctor::CtorFrom_Default)]
55 struct Struct(i32, f32);
Devin Jeanpierrea330af62022-06-09 17:03:45 -070056 unsafe impl ::ctor::RecursivelyPinned for Struct {
57 type CtorInitializedFields = Self;
58 }
Devin Jeanpierref643afa2022-02-23 20:50:48 +000059 impl !Unpin for Struct {}
60
61 ::ctor::emplace! {let p = <Struct as ::ctor::CtorNew<()>>::ctor_new(()); }
62 assert_eq!(p.0, 0);
63 assert_eq!(p.1, 0.0);
64}
65
66#[test]
Devin Jeanpierre239f7612022-05-09 06:09:08 -070067fn test_recursively_pinned_unit_struct() {
68 #[::ctor::recursively_pinned]
69 struct S;
Devin Jeanpierre57aac932022-05-17 17:18:44 -070070 let _ = Box::pin(S).as_mut().project_pin();
71 assert_eq!(::std::mem::size_of::<::ctor::project_pin_type!(S)>(), 0);
Devin Jeanpierre239f7612022-05-09 06:09:08 -070072}
73
74#[test]
75fn test_recursively_pinned_fieldless_struct() {
76 #[::ctor::recursively_pinned]
77 struct S {}
Devin Jeanpierred6f3e2a2022-07-20 18:45:42 -070078 let _ = Box::pin(S {
79 __must_use_ctor_to_initialize: [], // for tests only!
80 })
81 .as_mut()
82 .project_pin();
Devin Jeanpierre57aac932022-05-17 17:18:44 -070083 assert_eq!(::std::mem::size_of::<::ctor::project_pin_type!(S)>(), 0);
Devin Jeanpierre239f7612022-05-09 06:09:08 -070084}
85
86#[test]
87fn test_recursively_pinned_fieldless_tuple_struct() {
88 #[::ctor::recursively_pinned]
89 struct S();
Devin Jeanpierre57aac932022-05-17 17:18:44 -070090 let _ = Box::pin(S()).as_mut().project_pin();
91 assert_eq!(::std::mem::size_of::<::ctor::project_pin_type!(S)>(), 0);
Devin Jeanpierre239f7612022-05-09 06:09:08 -070092}
93
94#[test]
95fn test_recursively_pinned_fieldless_enum() {
96 #[::ctor::recursively_pinned]
97 enum E {
98 A,
99 }
Devin Jeanpierre57aac932022-05-17 17:18:44 -0700100 let <::ctor::project_pin_type!(E)>::A = Box::pin(E::A).as_mut().project_pin();
101 assert_eq!(::std::mem::size_of::<::ctor::project_pin_type!(E)>(), 0);
Devin Jeanpierre239f7612022-05-09 06:09:08 -0700102}
103
104#[test]
Devin Jeanpierrea858e6b2022-05-09 08:54:15 -0700105fn test_recursively_pinned_in_module() {
106 mod submodule {
107 #[::ctor::recursively_pinned]
108 pub struct S;
109 }
Devin Jeanpierre57aac932022-05-17 17:18:44 -0700110 let _: ::ctor::project_pin_type!(submodule::S) = Box::pin(submodule::S).as_mut().project_pin();
Devin Jeanpierrea858e6b2022-05-09 08:54:15 -0700111}
112
113#[test]
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000114fn test_recursively_pinned_struct() {
115 #[::ctor::recursively_pinned]
116 struct S {
117 x: i32,
118 }
Devin Jeanpierred6f3e2a2022-07-20 18:45:42 -0700119 let _: ::std::pin::Pin<&mut i32> = Box::pin(S {
120 x: 42,
121 __must_use_ctor_to_initialize: [], // for tests only!
122 })
123 .as_mut()
124 .project_pin()
125 .x;
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000126}
127
128#[test]
129fn test_recursively_pinned_tuple_struct() {
130 #[::ctor::recursively_pinned]
131 struct S(i32);
Devin Jeanpierre57aac932022-05-17 17:18:44 -0700132 let _: ::std::pin::Pin<&mut i32> = Box::pin(S(42)).as_mut().project_pin().0;
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000133}
134
135#[test]
136fn test_recursively_pinned_enum_struct() {
Devin Jeanpierre1c28ff22022-05-09 06:04:57 -0700137 #[::ctor::recursively_pinned]
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000138 enum E {
139 A { x: i32 },
140 }
Devin Jeanpierre57aac932022-05-17 17:18:44 -0700141 match Box::pin(E::A { x: 42 }).as_mut().project_pin() {
142 <::ctor::project_pin_type!(E)>::A { x } => {
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000143 let _: ::std::pin::Pin<&mut i32> = x;
144 }
145 }
146}
147
148#[test]
149fn test_recursively_pinned_enum_tuple() {
Devin Jeanpierre1c28ff22022-05-09 06:04:57 -0700150 #[::ctor::recursively_pinned]
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000151 enum E {
152 A(i32),
153 }
Devin Jeanpierre57aac932022-05-17 17:18:44 -0700154 match Box::pin(E::A(42)).as_mut().project_pin() {
155 <::ctor::project_pin_type!(E)>::A(x) => {
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000156 let _: ::std::pin::Pin<&mut i32> = x;
157 }
158 }
159}
160
161#[test]
Devin Jeanpierreab912362022-06-09 16:49:52 -0700162fn test_recursively_pinned_generic() {
163 #[::ctor::recursively_pinned]
164 struct S<'proj, 'proj_2: 'proj, 'proj_4, T>
165 where
166 'proj_4: 'proj_2,
167 {
168 x: T,
169 /// 'proj* are not really used, but exist to try to throw a wrench in
170 /// the works.
171 _phantom: ::std::marker::PhantomData<&'proj &'proj_2 &'proj_4 T>,
172 }
Devin Jeanpierred6f3e2a2022-07-20 18:45:42 -0700173 let _: ::std::pin::Pin<&mut i32> = Box::pin(S::<i32> {
174 x: 42,
175 _phantom: ::std::marker::PhantomData,
176 __must_use_ctor_to_initialize: [], // for tests only!
177 })
178 .as_mut()
179 .project_pin()
180 .x;
Devin Jeanpierreab912362022-06-09 16:49:52 -0700181}
182
Devin Jeanpierree9866732022-07-25 05:52:09 -0700183#[test]
184fn test_recursively_pinned_struct_derive_default() {
185 #[::ctor::recursively_pinned]
186 #[derive(::ctor::CtorFrom_Default)]
187 struct Struct {
188 x: i32,
189 y: f32,
190 }
191
192 ::ctor::emplace! {
193 let p = <Struct as ::ctor::CtorNew<()>>::ctor_new(());
194 }
195 assert_eq!(p.x, 0);
196 assert_eq!(p.y, 0.0);
197}
Devin Jeanpierref643afa2022-02-23 20:50:48 +0000198
199/// The same as the previous test, but with the attribute order swapped.
200/// This only compiles with macro_attributes_in_derive_output.
201#[test]
202fn test_derive_default_recursively_pinned_struct() {
203 #[derive(::ctor::CtorFrom_Default)]
204 #[::ctor::recursively_pinned]
205 struct Struct {
206 x: i32,
207 y: f32,
208 }
209
210 ::ctor::emplace! {let p = <Struct as ::ctor::CtorNew<()>>::ctor_new(()); }
211 assert_eq!(p.x, 0);
212 assert_eq!(p.y, 0.0);
213}
214
215#[test]
216fn test_recursively_pinned_actually_pinned() {
217 #[::ctor::recursively_pinned]
218 struct Struct {
219 x: i32,
220 y: f32,
221 pin: ::std::marker::PhantomPinned,
222 }
223
224 ::ctor::emplace! {
225 let p = ::ctor::ctor!(Struct {
226 x: 0,
227 y: 0.0,
228 pin: ::ctor::PhantomPinnedCtor,
229 });
230 }
231 assert_eq!(p.x, 0);
232 assert_eq!(p.y, 0.0);
233 // TODO(jeanpierreda): negative compilation test for e.g. `p.x = 1;`
234}
Devin Jeanpierrebe1efd22022-05-10 16:52:07 -0700235
236// TODO(jeanpierreda): negative compilation tests for invalid parameters to
237// #[recursively_pinned]:
238// * unknown parameter
239// * passing the same parameter twice
240// * extra parameters after parameter parsing is complete
241
242// TODO(jeanpierreda): negative compilation tests for Drop / PinnedDrop failures:
243// * implemented Drop
244// * forgot to implement PinnedDrop
245// * implemented PinnedDrop, but forgot to pass in PinnedDrop to
246// `::ctor::recursively_pinned`.
247
248#[test]
249fn test_pinned_drop() {
250 use ::std::cell::Cell;
251 use ::std::rc::Rc;
252
253 #[::ctor::recursively_pinned(PinnedDrop)]
254 struct DropStruct(Rc<Cell<bool>>);
255 impl ::ctor::PinnedDrop for DropStruct {
256 unsafe fn pinned_drop(self: ::std::pin::Pin<&mut Self>) {
Devin Jeanpierre57aac932022-05-17 17:18:44 -0700257 (&*self.project_pin().0).set(true);
Devin Jeanpierrebe1efd22022-05-10 16:52:07 -0700258 }
259 }
260
261 let called_drop = Rc::new(Cell::new(false));
262 let _ = DropStruct(called_drop.clone());
263 assert!(called_drop.get(), "PinnedDrop::pinned_drop was not called");
264}