More robust test for definition reordering.

Before this CL definition reordering *was* covered by an end-to-end test
under `cc_bindings_from_rs/test/structs`, but:

1) it was unnecessarily tangled with test of other features and
2) it only required reordering if bindings would be generated in the
   original source order, and
3) it didn't force a module/namespace to be split in two chunks (which
   is why namespace handling in b/258265044 isn't done top-down).

This CL tweaks to tests to fix these issues.

PiperOrigin-RevId: 495495236
diff --git a/cc_bindings_from_rs/test/structs/structs.rs b/cc_bindings_from_rs/test/structs/structs.rs
index d71cb92..8102b65 100644
--- a/cc_bindings_from_rs/test/structs/structs.rs
+++ b/cc_bindings_from_rs/test/structs/structs.rs
@@ -5,37 +5,91 @@
 //! This crate is used as a test input for `cc_bindings_from_rs` and the
 //! generated C++ bindings are then tested via `structs_test.cc`.
 
-pub fn create_repr_c_point_via_free_function(x: i32, y: i32) -> ReprCPoint {
-    ReprCPoint { x, y }
+/// Test for a `#[repr(C)` struct.
+pub mod repr_c {
+
+    #[repr(C)]
+    pub struct Point {
+        pub x: i32,
+        pub y: i32,
+    }
+
+    pub fn create(x: i32, y: i32) -> Point {
+        Point { x, y }
+    }
+
+    pub fn get_x(p: Point) -> i32 {
+        p.x
+    }
 }
 
-pub fn get_x_of_repr_c_point_via_free_function(p: ReprCPoint) -> i32 {
-    p.x
+/// Test for a struct using default layout (i.e. one without an explicit
+/// `#[repr(C)]` or similar attribute).  Among other things, it tests that
+/// building generated `..._cc_api_impl.rs` will not warn about
+/// `improper_ctypes_definitions` (search for this warning name in `bindings.rs`
+/// for a longer explanation of why suppressing this warning is okay).
+pub mod default_repr {
+
+    pub struct Point {
+        pub x: i32,
+        pub y: i32,
+    }
+
+    pub fn create(x: i32, y: i32) -> Point {
+        Point { x, y }
+    }
+
+    pub fn get_x(p: Point) -> i32 {
+        p.x
+    }
 }
 
-pub fn create_default_repr_point_via_free_function(x: i32, y: i32) -> DefaultReprPoint {
-    DefaultReprPoint { x, y }
-}
-
-pub fn get_x_of_default_repr_point_via_free_function(p: DefaultReprPoint) -> i32 {
-    p.x
-}
-
-// `ReprCPoint` is defined *after* functions that take or return this type,
-// because preserving this order in the generated `..._cc_api.h` file would
-// trigger a C++ error (because in C++ one can't refer to a struct before it has
-// been defined).
-#[repr(C)]
-pub struct ReprCPoint {
-    pub x: i32,
-    pub y: i32,
-}
-
-// `DefaultReprPoint` is defined *after* functions that take or return this
-// type, because preserving this order in the generated `..._cc_api.h` file
-// would trigger a C++ error (because in C++ one can't refer to a struct before
-// it has been defined).
-pub struct DefaultReprPoint {
-    pub x: i32,
-    pub y: i32,
+/// This module provides test coverage for reordering the generated bindings in
+/// a way that ensures that C++ structs are defined *before* being referring to
+/// them when (say) declaring a function that returns the struct by value, or
+/// takes it by value as an argument.
+///
+/// This module has been structured in a way that forces at least one submodule
+/// to be broken up into 2 separate chunks.  Definition dependencies force
+/// bindings from one of the structs to come first - let's assume that `m1::S1`
+/// comes first (the case where `m2::S2` comes first is symmetrical -
+/// all the same conclusions apply).  Before `m1::create_S2` can be declared,
+/// `m1::S2` needs to be defined.  This means that the order will be: `m1::S1`,
+/// ..., `m2::S2`, ..., `m1::create_S2` - the `m1` module has to be split into
+/// two non-contiguous chunks (in the generated bindings):
+///
+///     ```cpp
+///     namespace m1 {  // <- FIRST CHUNK OF `mod m1`
+///         struct S1 { ... };
+///     }
+///
+///     namespace m2 {
+///         struct S2 { ... };
+///     }
+///
+///     namespace m1 {  // <- SECOND CHUNK OF `mod m1`
+///         S2 create_s2();
+///     }
+///     ```
+pub mod reordering_defs {
+    pub mod m1 {
+        use super::m2::S2;
+        pub struct S1(pub i32);
+        pub fn create_s2() -> S2 {
+            S2(123)
+        }
+        pub fn get_int_from_s2(s2: S2) -> i32 {
+            s2.0
+        }
+    }
+    pub mod m2 {
+        use super::m1::S1;
+        pub struct S2(pub i32);
+        pub fn create_s1() -> S1 {
+            S1(456)
+        }
+        pub fn get_int_from_s1(s1: S1) -> i32 {
+            s1.0
+        }
+    }
 }
diff --git a/cc_bindings_from_rs/test/structs/structs_test.cc b/cc_bindings_from_rs/test/structs/structs_test.cc
index edd2185..9bca5d7 100644
--- a/cc_bindings_from_rs/test/structs/structs_test.cc
+++ b/cc_bindings_from_rs/test/structs/structs_test.cc
@@ -12,17 +12,24 @@
 namespace {
 
 TEST(StructsTest, ReprCPointReturnedOrTakenByValue) {
-  structs::ReprCPoint p =
-      structs::create_repr_c_point_via_free_function(123, 456);
-  EXPECT_EQ(123,
-            structs::get_x_of_repr_c_point_via_free_function(std::move(p)));
+  structs::repr_c::Point p = structs::repr_c::create(123, 456);
+  EXPECT_EQ(123, structs::repr_c::get_x(std::move(p)));
 }
 
 TEST(StructsTest, DefaultReprPointReturnedOrTakenByValue) {
-  structs::DefaultReprPoint p =
-      structs::create_default_repr_point_via_free_function(123, 456);
-  EXPECT_EQ(123, structs::get_x_of_default_repr_point_via_free_function(
-                     std::move(p)));
+  structs::default_repr::Point p = structs::default_repr::create(123, 456);
+  EXPECT_EQ(123, structs::default_repr::get_x(std::move(p)));
+}
+
+TEST(StructsTest, ReorderingDefs) {
+  namespace m1 = structs::reordering_defs::m1;
+  namespace m2 = structs::reordering_defs::m2;
+
+  m1::S1 s1 = m2::create_s1();
+  EXPECT_EQ(456, m2::get_int_from_s1(std::move(s1)));
+
+  m2::S2 s2 = m1::create_s2();
+  EXPECT_EQ(123, m1::get_int_from_s2(std::move(s2)));
 }
 
 }  // namespace