Migrate some unit tests from ir.rs to ir_from_cc_test using assert_ir_matches
PiperOrigin-RevId: 416796788
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index a0e900c..05a390c 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -9,6 +9,7 @@
use serde::Deserialize;
use std::collections::HashMap;
use std::convert::TryFrom;
+use std::fmt;
use std::io::Read;
pub const TESTING_TARGET: &str = "//test:testing_target";
@@ -116,11 +117,17 @@
pub cc_type: CcType,
}
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
+#[derive(PartialEq, Eq, Hash, Clone, Deserialize)]
pub struct Identifier {
pub identifier: String,
}
+impl fmt::Debug for Identifier {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(&format!("\"{}\"", &self.identifier))
+ }
+}
+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Deserialize)]
#[serde(transparent)]
pub struct DeclId(pub usize);
@@ -144,7 +151,7 @@
}
}
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
+#[derive(PartialEq, Eq, Hash, Clone, Deserialize)]
pub enum UnqualifiedIdentifier {
Identifier(Identifier),
Constructor,
@@ -160,6 +167,16 @@
}
}
+impl fmt::Debug for UnqualifiedIdentifier {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ UnqualifiedIdentifier::Identifier(identifier) => fmt::Debug::fmt(identifier, f),
+ UnqualifiedIdentifier::Constructor => f.write_str("Constructor"),
+ UnqualifiedIdentifier::Destructor => f.write_str("Destructor"),
+ }
+ }
+}
+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
pub enum ReferenceQualification {
LValue,
@@ -453,6 +470,24 @@
use super::*;
#[test]
+ fn test_identifier_debug_print() {
+ assert_eq!(format!("{:?}", Identifier { identifier: "hello".to_string() }), "\"hello\"");
+ }
+
+ #[test]
+ fn test_unqualified_identifier_debug_print() {
+ assert_eq!(
+ format!(
+ "{:?}",
+ UnqualifiedIdentifier::Identifier(Identifier { identifier: "hello".to_string() })
+ ),
+ "\"hello\""
+ );
+ assert_eq!(format!("{:?}", UnqualifiedIdentifier::Constructor), "Constructor");
+ assert_eq!(format!("{:?}", UnqualifiedIdentifier::Destructor), "Destructor");
+ }
+
+ #[test]
fn test_used_headers() {
let input = r#"
{
@@ -468,265 +503,4 @@
};
assert_eq!(ir.flat_ir, expected);
}
-
- #[test]
- fn test_member_access_specifiers() {
- let input = r#"
- {
- "current_target": "//foo:bar",
- "items": [
- { "Record" : {
- "identifier": {"identifier": "SomeStruct" },
- "id": 42,
- "owning_target": "//foo:bar",
- "fields": [
- {
- "identifier": {"identifier": "public_int" },
- "type": {
- "rs_type": {"name": "i32", "lifetime_args": [], "type_args": []},
- "cc_type": {"name": "int", "is_const": false, "type_args": []}
- },
- "access": "Public",
- "offset": 0
- },
- {
- "identifier": {"identifier": "protected_int" },
- "type": {
- "rs_type": {"name": "i32", "lifetime_args": [], "type_args": []},
- "cc_type": {"name": "int", "is_const": false, "type_args": []}
- },
- "access": "Protected",
- "offset": 32
- },
- {
- "identifier": {"identifier": "private_int" },
- "type": {
- "rs_type": {"name": "i32", "lifetime_args": [], "type_args": []},
- "cc_type": {"name": "int", "is_const": false, "type_args": []}
- },
- "access": "Private",
- "offset": 64
- }
- ],
- "lifetime_params": [],
- "size": 12,
- "alignment": 4,
- "copy_constructor": {
- "definition": "NontrivialUserDefined",
- "access": "Private"
- },
- "move_constructor": {
- "definition": "Deleted",
- "access": "Protected"
- },
- "destructor": {
- "definition": "Trivial",
- "access": "Public"
- },
- "is_trivial_abi": true
- }}
- ]
- }
- "#;
- let ir = deserialize_ir(input.as_bytes()).unwrap();
- let expected = FlatIR {
- used_headers: vec![],
- current_target: "//foo:bar".into(),
- items: vec![Item::Record(Record {
- identifier: Identifier { identifier: "SomeStruct".to_string() },
- id: DeclId(42),
- owning_target: "//foo:bar".into(),
- doc_comment: None,
- fields: vec![
- Field {
- identifier: Identifier { identifier: "public_int".to_string() },
- doc_comment: None,
- type_: MappedType {
- rs_type: RsType {
- name: "i32".to_string().into(),
- lifetime_args: vec![],
- type_args: vec![],
- decl_id: None,
- },
- cc_type: CcType {
- name: "int".to_string().into(),
- is_const: false,
- type_args: vec![],
- decl_id: None,
- },
- },
- access: AccessSpecifier::Public,
- offset: 0,
- },
- Field {
- identifier: Identifier { identifier: "protected_int".to_string() },
- doc_comment: None,
- type_: MappedType {
- rs_type: RsType {
- name: "i32".to_string().into(),
- lifetime_args: vec![],
- type_args: vec![],
- decl_id: None,
- },
- cc_type: CcType {
- name: "int".to_string().into(),
- is_const: false,
- type_args: vec![],
- decl_id: None,
- },
- },
- access: AccessSpecifier::Protected,
- offset: 32,
- },
- Field {
- identifier: Identifier { identifier: "private_int".to_string() },
- doc_comment: None,
- type_: MappedType {
- rs_type: RsType {
- name: "i32".to_string().into(),
- lifetime_args: vec![],
- type_args: vec![],
- decl_id: None,
- },
- cc_type: CcType {
- name: "int".to_string().into(),
- is_const: false,
- type_args: vec![],
- decl_id: None,
- },
- },
- access: AccessSpecifier::Private,
- offset: 64,
- },
- ],
- lifetime_params: vec![],
- size: 12,
- alignment: 4,
- copy_constructor: SpecialMemberFunc {
- definition: SpecialMemberDefinition::NontrivialUserDefined,
- access: AccessSpecifier::Private,
- },
- move_constructor: SpecialMemberFunc {
- definition: SpecialMemberDefinition::Deleted,
- access: AccessSpecifier::Protected,
- },
- destructor: SpecialMemberFunc {
- definition: SpecialMemberDefinition::Trivial,
- access: AccessSpecifier::Public,
- },
- is_trivial_abi: true,
- })],
- };
- assert_eq!(ir.flat_ir, expected);
- }
-
- #[test]
- fn test_pointer_member_variable() {
- let input = r#"
- {
- "current_target": "//foo:bar",
- "items": [
- { "Record": {
- "identifier": {"identifier": "SomeStruct" },
- "id": 42,
- "owning_target": "//foo:bar",
- "fields": [
- {
- "identifier": {"identifier": "ptr" },
- "type": {
- "rs_type": {"name": "*mut", "lifetime_args": [], "type_args": [
- {"name": "SomeStruct", "lifetime_args": [], "type_args": [], "decl_id": 42}
- ]},
- "cc_type": { "name": "*", "is_const": false, "type_args": [
- {
- "name": "SomeStruct",
- "is_const": false,
- "type_args": [],
- "decl_id": 42
- }
- ]}
- },
- "access": "Public",
- "offset": 0
- }
- ],
- "lifetime_params": [],
- "size": 8,
- "alignment": 8,
- "copy_constructor": {
- "definition": "Trivial",
- "access": "Public"
- },
- "move_constructor": {
- "definition": "Trivial",
- "access": "Public"
- },
- "destructor": {
- "definition": "Trivial",
- "access": "Public"
- },
- "is_trivial_abi": true
- }}
- ]
- }
- "#;
- let ir = deserialize_ir(input.as_bytes()).unwrap();
- let expected = FlatIR {
- used_headers: vec![],
- current_target: "//foo:bar".into(),
- items: vec![Item::Record(Record {
- identifier: Identifier { identifier: "SomeStruct".to_string() },
- id: DeclId(42),
- owning_target: "//foo:bar".into(),
- doc_comment: None,
- fields: vec![Field {
- identifier: Identifier { identifier: "ptr".to_string() },
- doc_comment: None,
- type_: MappedType {
- rs_type: RsType {
- name: "*mut".to_string().into(),
- decl_id: None,
- lifetime_args: vec![],
- type_args: vec![RsType {
- name: "SomeStruct".to_string().into(),
- lifetime_args: vec![],
- type_args: vec![],
- decl_id: Some(DeclId(42)),
- }],
- },
- cc_type: CcType {
- name: "*".to_string().into(),
- is_const: false,
- decl_id: None,
- type_args: vec![CcType {
- name: "SomeStruct".to_string().into(),
- is_const: false,
- type_args: vec![],
- decl_id: Some(DeclId(42)),
- }],
- },
- },
- access: AccessSpecifier::Public,
- offset: 0,
- }],
- lifetime_params: vec![],
- size: 8,
- alignment: 8,
- move_constructor: SpecialMemberFunc {
- definition: SpecialMemberDefinition::Trivial,
- access: AccessSpecifier::Public,
- },
- copy_constructor: SpecialMemberFunc {
- definition: SpecialMemberDefinition::Trivial,
- access: AccessSpecifier::Public,
- },
- destructor: SpecialMemberFunc {
- definition: SpecialMemberDefinition::Trivial,
- access: AccessSpecifier::Public,
- },
- is_trivial_abi: true,
- })],
- };
- assert_eq!(ir.flat_ir, expected);
- }
}
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index 1148141..bc22b81 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -8,8 +8,10 @@
use ir::*;
use ir_testing::*;
use itertools::Itertools;
+use quote::quote;
use std::collections::HashMap;
use std::iter::Iterator;
+use token_stream_matchers::{assert_ir_matches, assert_ir_not_matches};
// TODO(mboehme): If we start needing to match on parts of the IR in tests,
// check out the crate https://crates.io/crates/galvanic-assert.
@@ -69,13 +71,146 @@
#[test]
fn test_functions_from_dependency_are_not_emitted() -> Result<()> {
let ir = ir_from_cc_dependency("int Add(int a, int b);", "int Multiply(int a, int b);")?;
- let names = ir.functions().map(|i| i.name.identifier_as_str().unwrap()).collect_vec();
- assert_strings_contain(names.as_slice(), "Add");
- assert_strings_dont_contain(names.as_slice(), "Multiply");
+ assert_ir_matches!(ir, quote! { Func { name: "Add" ... } });
+ assert_ir_not_matches!(ir, quote! { Func { name: "Multiply" ... } });
Ok(())
}
#[test]
+fn test_record_member_variable_access_specifiers() {
+ let ir = ir_from_cc(
+ "
+ struct SomeStruct {
+ public:
+ int public_int;
+ protected:
+ int protected_int;
+ private:
+ int private_int;
+ };
+ ",
+ )
+ .unwrap();
+
+ assert_ir_matches!(
+ ir,
+ quote! {
+ Record {
+ identifier: "SomeStruct" ...
+ fields: [
+ Field {
+ identifier: "public_int" ...
+ access: Public ...
+ },
+ Field {
+ identifier: "protected_int" ...
+ access: Protected ...
+ },
+ Field {
+ identifier: "private_int" ...
+ access: Private ...
+ },
+ ] ...
+ }
+ }
+ );
+}
+
+#[test]
+fn test_record_special_member_access_specifiers() {
+ let ir = ir_from_cc(
+ "
+ struct SomeStruct {
+ private:
+ SomeStruct(SomeStruct& s);
+ protected:
+ SomeStruct(SomeStruct&& s);
+ public:
+ ~SomeStruct();
+ };
+ ",
+ )
+ .unwrap();
+
+ assert_ir_matches!(
+ ir,
+ quote! {
+ Record {
+ identifier: "SomeStruct" ...
+ copy_constructor: SpecialMemberFunc { ... access: Private ... },
+ move_constructor: SpecialMemberFunc { ... access: Protected ... },
+ destructor: SpecialMemberFunc { ... access: Public ... } ...
+ }
+ }
+ );
+}
+
+#[test]
+fn test_record_special_member_definition() {
+ let ir = ir_from_cc(
+ "
+ struct SomeStruct {
+ private:
+ SomeStruct(SomeStruct& s);
+ protected:
+ SomeStruct(SomeStruct&& s) = delete;
+ };
+ ",
+ )
+ .unwrap();
+
+ assert_ir_matches!(
+ ir,
+ quote! {
+ Record {
+ identifier: "SomeStruct" ...
+ copy_constructor: SpecialMemberFunc { definition: NontrivialUserDefined ... },
+ move_constructor: SpecialMemberFunc { definition: Deleted ... },
+ destructor: SpecialMemberFunc { definition: Trivial ... } ...
+ }
+ }
+ );
+}
+
+#[test]
+fn test_pointer_member_variable() {
+ let ir = ir_from_cc(
+ "struct SomeStruct {
+ SomeStruct* ptr;
+ };",
+ )
+ .unwrap();
+ assert_ir_matches!(
+ ir,
+ quote! {
+ Field {
+ identifier: "ptr" ...
+ type_: MappedType {
+ rs_type: RsType {
+ name: Some("*mut") ...
+ type_args: [RsType {
+ name: None ...
+ type_args: [],
+ decl_id: Some(...),
+ }],
+ decl_id: None,
+ },
+ cc_type: CcType {
+ name: Some("*") ...
+ type_args: [CcType {
+ name: None ...
+ type_args: [],
+ decl_id: Some(...),
+ }],
+ decl_id: None,
+ },
+ } ...
+ }
+ }
+ );
+}
+
+#[test]
fn test_doc_comment() -> Result<()> {
let ir = ir_from_cc(
r#"