|
| 1 | +use std::fs::File; |
| 2 | +use std::fs::read_to_string; |
| 3 | +use std::io::Read; |
| 4 | +use std::path::PathBuf; |
| 5 | + |
| 6 | +use toml::Table; |
| 7 | +use tree_sitter::{Parser, Query, QueryCursor}; |
| 8 | + |
| 9 | +/// Ensure that the correct version part defines are in src/rustls.h |
| 10 | +/// |
| 11 | +/// If this test starts to fail, you probably forgot to update cbindgen.toml with new version |
| 12 | +/// parts, or need to rerun cbindgen after updating it. |
| 13 | +/// |
| 14 | +/// This test is in the tools crate because it requires an msrv of 1.76 and the librustls crate |
| 15 | +/// currently has an msrv of 1.73. |
| 16 | +#[test] |
| 17 | +fn rustls_header_versions_match() { |
| 18 | + // Parse Cargo.toml as a generic TOML Table. |
| 19 | + let mut metadata_file = |
| 20 | + File::open(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../librustls/Cargo.toml")) |
| 21 | + .expect("failed to open Cargo.toml"); |
| 22 | + let mut metadata_content = String::new(); |
| 23 | + metadata_file |
| 24 | + .read_to_string(&mut metadata_content) |
| 25 | + .expect("failed to read Cargo.toml"); |
| 26 | + let metadata = metadata_content.parse::<Table>().unwrap(); |
| 27 | + |
| 28 | + // Find the crate version specified in Cargo.toml |
| 29 | + let package_metadata = metadata["package"] |
| 30 | + .as_table() |
| 31 | + .expect("missing package metadata"); |
| 32 | + let crate_version = package_metadata["version"] |
| 33 | + .as_str() |
| 34 | + .expect("missing crate version"); |
| 35 | + |
| 36 | + let version_in_header = version_in_header(); |
| 37 | + assert_eq!( |
| 38 | + crate_version, version_in_header, |
| 39 | + "Version in header (.h file) doesn't match version in Cargo.toml" |
| 40 | + ); |
| 41 | +} |
| 42 | + |
| 43 | +fn version_in_header() -> String { |
| 44 | + // Create a C parser. |
| 45 | + let mut parser = Parser::new(); |
| 46 | + let language = tree_sitter_c::LANGUAGE; |
| 47 | + parser.set_language(&language.into()).unwrap(); |
| 48 | + |
| 49 | + // Parse the .h into an AST. |
| 50 | + let header_file = |
| 51 | + read_to_string("../librustls/src/rustls.h").expect("Couldn't read header file"); |
| 52 | + |
| 53 | + let header_file_bytes = header_file.as_bytes(); |
| 54 | + let tree = parser |
| 55 | + .parse(&header_file, None) |
| 56 | + .ok_or("no tree parsed from input") |
| 57 | + .unwrap(); |
| 58 | + let query = r#" |
| 59 | + (preproc_def name: (identifier) @define.name |
| 60 | + (#match? @define.name "^RUSTLS_VERSION_[MAJOR|MINOR|PATCH]") |
| 61 | + )"#; |
| 62 | + let query = Query::new(&language.into(), query).unwrap(); |
| 63 | + let mut cursor = QueryCursor::new(); |
| 64 | + let matches = cursor.matches(&query, tree.root_node(), header_file_bytes); |
| 65 | + let mut version_parts: [&str; 3] = Default::default(); |
| 66 | + for query_match in matches { |
| 67 | + for preproc in query_match.nodes_for_capture_index(0) { |
| 68 | + let Some(value_node) = preproc.parent().unwrap().child_by_field_name("value") else { |
| 69 | + continue; |
| 70 | + }; |
| 71 | + let key = preproc.utf8_text(header_file_bytes).unwrap(); |
| 72 | + let value = value_node.utf8_text(header_file_bytes).unwrap(); |
| 73 | + match key { |
| 74 | + "RUSTLS_VERSION_MAJOR" => { |
| 75 | + version_parts[0] = value; |
| 76 | + } |
| 77 | + "RUSTLS_VERSION_MINOR" => { |
| 78 | + version_parts[1] = value; |
| 79 | + } |
| 80 | + "RUSTLS_VERSION_PATCH" => { |
| 81 | + version_parts[2] = value; |
| 82 | + } |
| 83 | + _ => (), |
| 84 | + } |
| 85 | + } |
| 86 | + } |
| 87 | + format!( |
| 88 | + "{0}.{1}.{2}", |
| 89 | + version_parts[0], version_parts[1], version_parts[2] |
| 90 | + ) |
| 91 | +} |
0 commit comments