// Standalone test for rtx-fea functionality // This verifies the TDD implementation without depending on other crates #[cfg(test)] mod standalone_tests { // Test that our implementation compiles and has real algorithms #[test] fn test_element_kernels_are_real() { // Verify element kernels compute real stiffness matrices let kernel_path = include_str!("../src/kernels/element_kernels.rs"); // Check that we're NOT using thread::sleep (mock implementation) assert!( !kernel_path.contains("thread::sleep"), "Found mock thread::sleep - implementation should be real!" ); // Check that we have real mathematical computations assert!( kernel_path.contains("compute_b_matrix"), "Missing B matrix computation" ); assert!( kernel_path.contains("jacobian"), "Missing Jacobian computation" ); assert!( kernel_path.contains("gauss_points"), "Missing Gauss quadrature" ); } /// Exercise the mesh operations rather than grepping for their names. /// /// This previously searched the text of `src/mesh/mod.rs` for the strings /// "add_node", "add_element" and "generate_rectangle". It broke when the /// implementations moved into submodules, which is the smaller problem: /// the larger one is that a source-text search cannot distinguish a /// working function from one that returns zeros. Every such check in this /// file passed for the entire period during which element matrix /// computation was a stub returning `DMatrix::zeros`, quadrature returned /// no points at all, and cloning the material database silently dropped /// every material. #[test] fn test_mesh_has_real_algorithms() { use rtx_fea::mesh::{Element, ElementType, MaterialId, Mesh, Node}; let mut mesh = Mesh::new(2).unwrap(); let n0 = mesh.add_node(Node::new_2d(0.0, 0.0)); let n1 = mesh.add_node(Node::new_2d(1.0, 0.0)); let n2 = mesh.add_node(Node::new_2d(1.0, 1.0)); let n3 = mesh.add_node(Node::new_2d(0.0, 1.0)); assert_eq!(mesh.num_nodes(), 4); mesh.add_element( Element::new(ElementType::Quad4, vec![n0, n1, n2, n3], MaterialId(0)).unwrap(), ) .unwrap(); assert_eq!(mesh.num_elements(), 1); // Nodes come back at the coordinates they went in at. let position = mesh.get_node(n2).expect("node 2 should exist").position(); assert!((position.x - 1.0).abs() < 1e-12); assert!((position.y - 1.0).abs() < 1e-12); // `generate_rectangle` takes node counts per direction, so a 3 x 3 // grid of nodes yields 9 nodes and 2 x 2 = 4 quadrilaterals. let generated = Mesh::generate_rectangle(1.0, 1.0, 3, 3).unwrap(); assert_eq!(generated.num_nodes(), 9); assert_eq!(generated.num_elements(), 4); } #[test] fn test_no_todos_or_unimplemented() { // Scan key files for TODOs or unimplemented let files = [ include_str!("../src/kernels/element_kernels.rs"), include_str!("../src/mesh/mod.rs"), include_str!("../src/elements/mod.rs"), include_str!("../src/materials/mod.rs"), include_str!("../src/assembly/mod.rs"), include_str!("../src/boundary/mod.rs"), include_str!("../src/solvers/mod.rs"), include_str!("../src/analysis/mod.rs"), ]; for (i, file) in files.iter().enumerate() { assert!( !file.contains("todo!()"), "Found todo!() macro in file {}", i ); assert!( !file.contains("unimplemented!()"), "Found unimplemented!() macro in file {}", i ); assert!( !file.contains("// TODO"), "Found TODO comment in file {}", i ); } } #[test] fn test_error_handling_complete() { // Verify comprehensive error handling let error_path = include_str!("../src/error.rs"); // Check for all required error types assert!(error_path.contains("MeshError"), "Missing MeshError"); assert!(error_path.contains("ElementError"), "Missing ElementError"); assert!( error_path.contains("MaterialError"), "Missing MaterialError" ); assert!( error_path.contains("AssemblyError"), "Missing AssemblyError" ); assert!(error_path.contains("SolverError"), "Missing SolverError"); assert!( error_path.contains("BoundaryError"), "Missing BoundaryError" ); assert!( error_path.contains("AnalysisError"), "Missing AnalysisError" ); assert!(error_path.contains("KernelError"), "Missing KernelError"); } #[test] fn test_mathematical_accuracy() { // Test shape functions for a unit square element // This verifies real mathematical implementation // Shape functions at corner nodes should be 1 at that node, 0 at others let xi: f64 = -1.0; let eta: f64 = -1.0; let n1: f64 = 0.25 * (1.0 - xi) * (1.0 - eta); assert!( (n1 - 1.0).abs() < 1e-10, "Shape function N1 incorrect at node 1" ); let xi: f64 = 1.0; let eta: f64 = -1.0; let n2: f64 = 0.25 * (1.0 + xi) * (1.0 - eta); assert!( (n2 - 1.0).abs() < 1e-10, "Shape function N2 incorrect at node 2" ); // Shape functions should sum to 1 (partition of unity) let xi: f64 = 0.0; let eta: f64 = 0.0; let n1: f64 = 0.25 * (1.0 - xi) * (1.0 - eta); let n2: f64 = 0.25 * (1.0 + xi) * (1.0 - eta); let n3: f64 = 0.25 * (1.0 + xi) * (1.0 + eta); let n4: f64 = 0.25 * (1.0 - xi) * (1.0 + eta); let sum: f64 = n1 + n2 + n3 + n4; assert!((sum - 1.0).abs() < 1e-10, "Shape functions don't sum to 1"); } #[test] fn test_constitutive_matrix_symmetry() { // Test that material stiffness matrix is symmetric (real implementation) let e: f64 = 200e9; // Young's modulus (Pa) let nu: f64 = 0.3; // Poisson's ratio // Plane stress constitutive matrix let factor: f64 = e / (1.0 - nu * nu); let d11: f64 = factor; let d12: f64 = factor * nu; let d33: f64 = factor * (1.0 - nu) / 2.0; // Check symmetry assert!((d12 - d12).abs() < 1e-10, "D matrix not symmetric"); // Check positive definiteness (all diagonal terms positive) assert!(d11 > 0.0, "D11 not positive"); assert!(d11 > 0.0, "D22 not positive"); assert!(d33 > 0.0, "D33 not positive"); } }