@@ -2,78 +2,185 @@ use askama::Template;
2
2
use quote:: ToTokens ;
3
3
4
4
use crate :: ffi_items:: FfiItems ;
5
- use crate :: generator:: GenerationError ;
6
5
use crate :: translator:: Translator ;
7
- use crate :: { MapInput , Result , TestGenerator } ;
6
+ use crate :: { BoxStr , MapInput , Result , TestGenerator , TranslationError } ;
8
7
9
8
/// Represents the Rust side of the generated testing suite.
10
9
#[ derive( Template , Clone ) ]
11
10
#[ template( path = "test.rs" ) ]
12
- pub ( crate ) struct RustTestTemplate < ' a > {
13
- ffi_items : & ' a FfiItems ,
14
- #[ expect( unused) ]
15
- generator : & ' a TestGenerator ,
11
+ pub ( crate ) struct RustTestTemplate {
12
+ pub ( crate ) template : TestTemplate ,
13
+ }
14
+
15
+ impl RustTestTemplate {
16
+ pub ( crate ) fn new (
17
+ ffi_items : & FfiItems ,
18
+ generator : & TestGenerator ,
19
+ ) -> Result < Self , TranslationError > {
20
+ Ok ( Self {
21
+ template : TestTemplate :: new ( ffi_items, generator) ?,
22
+ } )
23
+ }
16
24
}
17
25
18
26
/// Represents the C side of the generated testing suite.
19
27
#[ derive( Template , Clone ) ]
20
28
#[ template( path = "test.c" ) ]
21
- pub ( crate ) struct CTestTemplate < ' a > {
22
- translator : Translator ,
23
- ffi_items : & ' a FfiItems ,
24
- generator : & ' a TestGenerator ,
29
+ pub ( crate ) struct CTestTemplate {
30
+ pub ( crate ) template : TestTemplate ,
31
+ pub ( crate ) headers : Vec < String > ,
25
32
}
26
33
27
- impl < ' a > RustTestTemplate < ' a > {
28
- /// Create a new test template to test the given items.
29
- pub ( crate ) fn new ( ffi_items : & ' a FfiItems , generator : & ' a TestGenerator ) -> Self {
30
- Self {
31
- ffi_items,
32
- generator,
33
- }
34
+ impl CTestTemplate {
35
+ pub ( crate ) fn new (
36
+ ffi_items : & FfiItems ,
37
+ generator : & TestGenerator ,
38
+ ) -> Result < Self , TranslationError > {
39
+ Ok ( Self {
40
+ template : TestTemplate :: new ( ffi_items, generator) ?,
41
+ headers : generator. headers . clone ( ) ,
42
+ } )
34
43
}
35
44
}
36
45
37
- impl < ' a > CTestTemplate < ' a > {
38
- /// Create a new test template to test the given items.
39
- pub ( crate ) fn new ( ffi_items : & ' a FfiItems , generator : & ' a TestGenerator ) -> Self {
40
- Self {
46
+ /// Stores all information necessary for generation of tests for all items.
47
+ #[ derive( Clone , Debug , Default ) ]
48
+ pub ( crate ) struct TestTemplate {
49
+ pub ( crate ) const_cstr_tests : Vec < TestCstr > ,
50
+ pub ( crate ) const_tests : Vec < TestConst > ,
51
+ pub ( crate ) test_idents : Vec < BoxStr > ,
52
+ }
53
+
54
+ impl TestTemplate {
55
+ pub ( crate ) fn new (
56
+ ffi_items : & FfiItems ,
57
+ generator : & TestGenerator ,
58
+ ) -> Result < Self , TranslationError > {
59
+ let helper = TranslateHelper {
41
60
ffi_items,
42
- translator : Translator :: new ( ) ,
43
61
generator,
62
+ translator : Translator :: new ( ) ,
63
+ } ;
64
+
65
+ /* Figure out which tests are to be generated. */
66
+ // FIXME(ctest): Populate more test information, maybe extract into separate methods.
67
+ // The workflow would be to create a struct that stores information for the new test,
68
+ // and populating that struct here, so that the also things that have to be added to
69
+ // the test templates are the new tests parameterized by that struct.
70
+
71
+ let mut const_tests = vec ! [ ] ;
72
+ let mut const_cstr_tests = vec ! [ ] ;
73
+ for constant in ffi_items. constants ( ) {
74
+ if let syn:: Type :: Ptr ( ptr) = & constant. ty {
75
+ let is_const_c_char_ptr = matches ! (
76
+ & * ptr. elem,
77
+ syn:: Type :: Path ( path)
78
+ if path. path. segments. last( ) . unwrap( ) . ident == "c_char"
79
+ && ptr. mutability. is_none( )
80
+ ) ;
81
+ if is_const_c_char_ptr {
82
+ let item = TestCstr {
83
+ test_ident : cstr_test_ident ( constant. ident ( ) ) ,
84
+ rust_ident : constant. ident ( ) . into ( ) ,
85
+ c_ident : helper. c_ident ( constant) . into ( ) ,
86
+ c_type : helper. c_type ( constant) ?. into ( ) ,
87
+ } ;
88
+ const_cstr_tests. push ( item)
89
+ }
90
+ } else {
91
+ let item = TestConst {
92
+ test_ident : const_test_ident ( constant. ident ( ) ) ,
93
+ rust_ident : constant. ident . clone ( ) ,
94
+ rust_type : constant. ty . to_token_stream ( ) . to_string ( ) . into_boxed_str ( ) ,
95
+ c_ident : helper. c_ident ( constant) . into ( ) ,
96
+ c_type : helper. c_type ( constant) ?. into ( ) ,
97
+ } ;
98
+ const_tests. push ( item)
99
+ }
44
100
}
101
+
102
+ let mut test_idents = vec ! [ ] ;
103
+ test_idents. extend ( const_cstr_tests. iter ( ) . map ( |test| test. test_ident . clone ( ) ) ) ;
104
+ test_idents. extend ( const_tests. iter ( ) . map ( |test| test. test_ident . clone ( ) ) ) ;
105
+
106
+ Ok ( Self {
107
+ const_cstr_tests,
108
+ const_tests,
109
+ test_idents,
110
+ } )
45
111
}
112
+ }
113
+
114
+ /// Information required to test a constant CStr.
115
+ #[ derive( Clone , Debug ) ]
116
+ pub ( crate ) struct TestCstr {
117
+ pub ( crate ) test_ident : BoxStr ,
118
+ pub ( crate ) rust_ident : BoxStr ,
119
+ pub ( crate ) c_ident : BoxStr ,
120
+ pub ( crate ) c_type : BoxStr ,
121
+ }
122
+
123
+ /// Information required to test a constant.
124
+ #[ derive( Clone , Debug ) ]
125
+ pub ( crate ) struct TestConst {
126
+ pub ( crate ) test_ident : BoxStr ,
127
+ pub ( crate ) rust_ident : BoxStr ,
128
+ pub ( crate ) rust_type : BoxStr ,
129
+ pub ( crate ) c_ident : BoxStr ,
130
+ pub ( crate ) c_type : BoxStr ,
131
+ }
132
+
133
+ /// The Rust name of the cstr test.
134
+ ///
135
+ /// The C name of this same test is the same with `__` prepended.
136
+ fn cstr_test_ident ( ident : & str ) -> BoxStr {
137
+ format ! ( "ctest_const_cstr_{ident}" ) . into ( )
138
+ }
139
+
140
+ /// The Rust name of the const test.
141
+ ///
142
+ /// The C name of this test is the same with `__` prepended.
143
+ fn const_test_ident ( ident : & str ) -> BoxStr {
144
+ format ! ( "ctest_const_{ident}" ) . into ( )
145
+ }
46
146
147
+ /// Wrap methods that depend on both ffi items and the generator.
148
+ struct TranslateHelper < ' a > {
149
+ ffi_items : & ' a FfiItems ,
150
+ generator : & ' a TestGenerator ,
151
+ translator : Translator ,
152
+ }
153
+
154
+ impl < ' a > TranslateHelper < ' a > {
47
155
/// Returns the equivalent C/Cpp identifier of the Rust item.
48
- pub ( crate ) fn c_ident ( & self , item : impl Into < MapInput < ' a > > ) -> Result < String , GenerationError > {
156
+ pub ( crate ) fn c_ident ( & self , item : impl Into < MapInput < ' a > > ) -> String {
49
157
self . generator . map ( item)
50
158
}
51
159
52
160
/// Returns the equivalent C/Cpp type of the Rust item.
53
- pub ( crate ) fn c_type ( & self , item : impl Into < MapInput < ' a > > ) -> Result < String , GenerationError > {
54
- let item: MapInput < ' a > = item. into ( ) ;
161
+ pub ( crate ) fn c_type ( & self , item : impl Into < MapInput < ' a > > ) -> Result < String , TranslationError > {
162
+ let item: MapInput = item. into ( ) ;
55
163
56
164
let ( ident, ty) = match item {
57
- MapInput :: Const ( c) => ( c. ident ( ) , self . translator . translate_type ( & c. ty ) ) ,
58
- MapInput :: Alias ( a) => ( a. ident ( ) , self . translator . translate_type ( & a. ty ) ) ,
59
- MapInput :: Field ( _, f) => ( f. ident ( ) , self . translator . translate_type ( & f. ty ) ) ,
60
- MapInput :: Static ( s) => ( s. ident ( ) , self . translator . translate_type ( & s. ty ) ) ,
165
+ MapInput :: Const ( c) => ( c. ident ( ) , self . translator . translate_type ( & c. ty ) ? ) ,
166
+ MapInput :: Alias ( a) => ( a. ident ( ) , self . translator . translate_type ( & a. ty ) ? ) ,
167
+ MapInput :: Field ( _, f) => ( f. ident ( ) , self . translator . translate_type ( & f. ty ) ? ) ,
168
+ MapInput :: Static ( s) => ( s. ident ( ) , self . translator . translate_type ( & s. ty ) ? ) ,
61
169
MapInput :: Fn ( _) => unimplemented ! ( ) ,
62
170
MapInput :: Struct ( _) => unimplemented ! ( ) ,
63
171
MapInput :: StructType ( _) => panic ! ( "MapInput::StructType is not allowed!" ) ,
64
172
MapInput :: UnionType ( _) => panic ! ( "MapInput::UnionType is not allowed!" ) ,
65
173
MapInput :: Type ( _) => panic ! ( "MapInput::Type is not allowed!" ) ,
66
174
} ;
67
175
68
- let ty = ty. map_err ( |e| GenerationError :: TemplateRender ( "C" . to_string ( ) , e. to_string ( ) ) ) ?;
69
-
70
176
let item = if self . ffi_items . contains_struct ( ident) {
71
177
MapInput :: StructType ( & ty)
72
178
} else if self . ffi_items . contains_union ( ident) {
73
179
MapInput :: UnionType ( & ty)
74
180
} else {
75
181
MapInput :: Type ( & ty)
76
182
} ;
77
- self . generator . map ( item)
183
+
184
+ Ok ( self . generator . map ( item) )
78
185
}
79
186
}
0 commit comments