@@ -2,78 +2,185 @@ use askama::Template;
22use quote:: ToTokens ;
33
44use crate :: ffi_items:: FfiItems ;
5- use crate :: generator:: GenerationError ;
65use crate :: translator:: Translator ;
7- use crate :: { MapInput , Result , TestGenerator } ;
6+ use crate :: { BoxStr , MapInput , Result , TestGenerator , TranslationError } ;
87
98/// Represents the Rust side of the generated testing suite.
109#[ derive( Template , Clone ) ]
1110#[ 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+ }
1624}
1725
1826/// Represents the C side of the generated testing suite.
1927#[ derive( Template , Clone ) ]
2028#[ 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 > ,
2532}
2633
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+ } )
3443 }
3544}
3645
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 {
4160 ffi_items,
42- translator : Translator :: new ( ) ,
4361 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+ }
44100 }
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+ } )
45111 }
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+ }
46146
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 > {
47155 /// 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 {
49157 self . generator . map ( item)
50158 }
51159
52160 /// 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 ( ) ;
55163
56164 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 ) ? ) ,
61169 MapInput :: Fn ( _) => unimplemented ! ( ) ,
62170 MapInput :: Struct ( _) => unimplemented ! ( ) ,
63171 MapInput :: StructType ( _) => panic ! ( "MapInput::StructType is not allowed!" ) ,
64172 MapInput :: UnionType ( _) => panic ! ( "MapInput::UnionType is not allowed!" ) ,
65173 MapInput :: Type ( _) => panic ! ( "MapInput::Type is not allowed!" ) ,
66174 } ;
67175
68- let ty = ty. map_err ( |e| GenerationError :: TemplateRender ( "C" . to_string ( ) , e. to_string ( ) ) ) ?;
69-
70176 let item = if self . ffi_items . contains_struct ( ident) {
71177 MapInput :: StructType ( & ty)
72178 } else if self . ffi_items . contains_union ( ident) {
73179 MapInput :: UnionType ( & ty)
74180 } else {
75181 MapInput :: Type ( & ty)
76182 } ;
77- self . generator . map ( item)
183+
184+ Ok ( self . generator . map ( item) )
78185 }
79186}
0 commit comments