1
1
#![ cfg( not( feature = "capi" ) ) ]
2
2
use std:: fs:: File ;
3
+ use std:: fs:: read_to_string;
3
4
use std:: io:: Read ;
4
5
use std:: path:: PathBuf ;
5
6
6
7
use toml:: Table ;
8
+ use tree_sitter:: { Parser , Query , QueryCursor } ;
7
9
8
10
use rustls_ffi:: rustls_version;
9
11
@@ -12,8 +14,10 @@ use rustls_ffi::rustls_version;
12
14
/// In particular this ensures that the Rustls version reported in the rustls-ffi version string
13
15
/// matches the version of the Rustls dependency that rustls-ffi was built with.
14
16
///
17
+ /// It also ensures that the correct version parts defines are in src/rustls.h
18
+ ///
15
19
/// If this test starts to fail, you probably forgot to update `RUSTLS_CRATE_VERSION` in
16
- /// `build.rs`.
20
+ /// `build.rs`, or forgot to update cbindgen.toml with new version parts (or run cbindgen again) .
17
21
#[ cfg_attr( miri, ignore) ] // Requires file I/O
18
22
#[ test]
19
23
fn rustls_version_match ( ) {
@@ -71,4 +75,45 @@ fn rustls_version_match() {
71
75
rustls_crypto_provider,
72
76
]
73
77
) ;
78
+ let version_in_header = version_in_header ( ) ;
79
+ assert_eq ! ( crate_version, version_in_header, "Version in header (.h file) doesn't match version Cargo.toml" ) ;
80
+ }
81
+
82
+ #[ cfg_attr( miri, ignore) ] // Requires file I/O
83
+ fn version_in_header ( ) -> String {
84
+ // Create a C parser.
85
+ let mut parser = Parser :: new ( ) ;
86
+ let language = tree_sitter_c:: LANGUAGE ;
87
+ parser. set_language ( & language. into ( ) ) . unwrap ( ) ;
88
+
89
+ // Parse the .h into an AST.
90
+ let header_file = read_to_string ( "src/rustls.h" ) . expect ( "Couldn't read header file" ) ;
91
+
92
+ let header_file_bytes = header_file. as_bytes ( ) ;
93
+ let tree = parser
94
+ . parse ( & header_file, None )
95
+ . ok_or ( "no tree parsed from input" )
96
+ . unwrap ( ) ;
97
+ let root_node = tree. root_node ( ) ;
98
+ let query = r#"( preproc_def name: (identifier) @define.name )"# ;
99
+ let query = Query :: new ( & language. into ( ) , query) . unwrap ( ) ;
100
+ let mut cursor = QueryCursor :: new ( ) ;
101
+ let matches = cursor. matches ( & query, root_node, header_file_bytes) ;
102
+ let mut version_parts: [ & str ; 3 ] = Default :: default ( ) ;
103
+ for query_match in matches {
104
+ for preproc in query_match. nodes_for_capture_index ( 0 ) {
105
+ let parent = preproc. parent ( ) . unwrap ( ) ;
106
+ if let Some ( value_node) = parent. child_by_field_name ( "value" ) {
107
+ let key = preproc. utf8_text ( header_file_bytes) . unwrap ( ) ;
108
+ let value = value_node. utf8_text ( header_file_bytes) . unwrap ( ) ;
109
+ match key {
110
+ "RUSTLS_VERSION_MAJOR" => { version_parts[ 0 ] = value; }
111
+ "RUSTLS_VERSION_MINOR" => { version_parts[ 1 ] = value; }
112
+ "RUSTLS_VERSION_PATCH" => { version_parts[ 2 ] = value; }
113
+ _ => ( ) ,
114
+ }
115
+ }
116
+ }
117
+ }
118
+ return format ! ( "{0}.{1}.{2}" , version_parts[ 0 ] , version_parts[ 1 ] , version_parts[ 2 ] ) ;
74
119
}
0 commit comments