|
1 | 1 | //! Tests for semantic analysis components |
2 | 2 |
|
3 | 3 | use crate::{ |
4 | | - SymbolResolver, SymbolResolverConfig, ScopeManager, SymbolTable, |
5 | | - Symbol, SymbolKind, ReferenceType, SymbolReference, ScopeType |
| 4 | + SymbolResolver, SymbolResolverConfig, ScopeManager, SymbolTable, |
| 5 | + Symbol, SymbolKind, ReferenceType, SymbolReference, ScopeType, |
| 6 | + TypeExtractor, TypeExtractorConfig, TypeSignature, TypeEquivalence, |
| 7 | + TypeDependencyGraphBuilder, TypeRelationshipType |
6 | 8 | }; |
7 | 9 | use smart_diff_parser::{TreeSitterParser, Language, ParseResult}; |
8 | 10 | use std::collections::HashSet; |
@@ -380,3 +382,232 @@ mod symbol_table_tests { |
380 | 382 | assert_eq!(references[0].reference_type, ReferenceType::Call); |
381 | 383 | } |
382 | 384 | } |
| 385 | + |
| 386 | +#[cfg(test)] |
| 387 | +mod type_system_tests { |
| 388 | + use super::*; |
| 389 | + |
| 390 | + #[test] |
| 391 | + fn test_type_signature_parsing() { |
| 392 | + // Test simple type |
| 393 | + let simple_type = TypeSignature::parse("String").unwrap(); |
| 394 | + assert_eq!(simple_type.base_type, "String"); |
| 395 | + assert!(simple_type.generic_params.is_empty()); |
| 396 | + assert_eq!(simple_type.array_dimensions, 0); |
| 397 | + |
| 398 | + // Test generic type |
| 399 | + let generic_type = TypeSignature::parse("List<String>").unwrap(); |
| 400 | + assert_eq!(generic_type.base_type, "List"); |
| 401 | + assert_eq!(generic_type.generic_params.len(), 1); |
| 402 | + assert_eq!(generic_type.generic_params[0].base_type, "String"); |
| 403 | + |
| 404 | + // Test nested generics |
| 405 | + let nested_generic = TypeSignature::parse("Map<String, List<Integer>>").unwrap(); |
| 406 | + assert_eq!(nested_generic.base_type, "Map"); |
| 407 | + assert_eq!(nested_generic.generic_params.len(), 2); |
| 408 | + assert_eq!(nested_generic.generic_params[0].base_type, "String"); |
| 409 | + assert_eq!(nested_generic.generic_params[1].base_type, "List"); |
| 410 | + assert_eq!(nested_generic.generic_params[1].generic_params[0].base_type, "Integer"); |
| 411 | + |
| 412 | + // Test array type |
| 413 | + let array_type = TypeSignature::parse("String[][]").unwrap(); |
| 414 | + assert_eq!(array_type.base_type, "String"); |
| 415 | + assert_eq!(array_type.array_dimensions, 2); |
| 416 | + |
| 417 | + // Test nullable type |
| 418 | + let nullable_type = TypeSignature::parse("String?").unwrap(); |
| 419 | + assert_eq!(nullable_type.base_type, "String"); |
| 420 | + assert!(nullable_type.is_nullable); |
| 421 | + } |
| 422 | + |
| 423 | + #[test] |
| 424 | + fn test_type_equivalence() { |
| 425 | + // Test exact match |
| 426 | + assert!(TypeEquivalence::are_equivalent("String", "String")); |
| 427 | + |
| 428 | + // Test normalized equivalence |
| 429 | + assert!(TypeEquivalence::are_equivalent("int", "i32")); |
| 430 | + assert!(TypeEquivalence::are_equivalent("String", "string")); |
| 431 | + assert!(TypeEquivalence::are_equivalent("bool", "Boolean")); |
| 432 | + |
| 433 | + // Test non-equivalent types |
| 434 | + assert!(!TypeEquivalence::are_equivalent("String", "Integer")); |
| 435 | + assert!(!TypeEquivalence::are_equivalent("int", "float")); |
| 436 | + } |
| 437 | + |
| 438 | + #[test] |
| 439 | + fn test_complex_type_equivalence() { |
| 440 | + let type1 = TypeSignature::parse("List<String>").unwrap(); |
| 441 | + let type2 = TypeSignature::parse("List<String>").unwrap(); |
| 442 | + let type3 = TypeSignature::parse("List<Integer>").unwrap(); |
| 443 | + |
| 444 | + assert!(TypeEquivalence::are_complex_types_equivalent(&type1, &type2)); |
| 445 | + assert!(!TypeEquivalence::are_complex_types_equivalent(&type1, &type3)); |
| 446 | + } |
| 447 | + |
| 448 | + #[test] |
| 449 | + fn test_type_similarity_calculation() { |
| 450 | + let type1 = TypeSignature::parse("List<String>").unwrap(); |
| 451 | + let type2 = TypeSignature::parse("List<String>").unwrap(); |
| 452 | + let type3 = TypeSignature::parse("List<Integer>").unwrap(); |
| 453 | + let type4 = TypeSignature::parse("ArrayList<String>").unwrap(); |
| 454 | + |
| 455 | + // Identical types should have similarity 1.0 |
| 456 | + assert_eq!(TypeEquivalence::calculate_type_similarity(&type1, &type2), 1.0); |
| 457 | + |
| 458 | + // Different generic parameters should have lower similarity |
| 459 | + let similarity_diff_generic = TypeEquivalence::calculate_type_similarity(&type1, &type3); |
| 460 | + assert!(similarity_diff_generic < 1.0); |
| 461 | + assert!(similarity_diff_generic > 0.0); |
| 462 | + |
| 463 | + // Related types should have some similarity |
| 464 | + let similarity_related = TypeEquivalence::calculate_type_similarity(&type1, &type4); |
| 465 | + assert!(similarity_related > 0.0); |
| 466 | + assert!(similarity_related < 1.0); |
| 467 | + } |
| 468 | + |
| 469 | + #[test] |
| 470 | + fn test_type_signature_string_conversion() { |
| 471 | + let type_sig = TypeSignature::new("List".to_string()) |
| 472 | + .with_generics(vec![TypeSignature::new("String".to_string())]) |
| 473 | + .with_array_dimensions(1) |
| 474 | + .with_nullable(true); |
| 475 | + |
| 476 | + let type_string = type_sig.to_string(); |
| 477 | + assert!(type_string.contains("List")); |
| 478 | + assert!(type_string.contains("String")); |
| 479 | + assert!(type_string.contains("[]")); |
| 480 | + assert!(type_string.contains("?")); |
| 481 | + } |
| 482 | +} |
| 483 | + |
| 484 | +#[cfg(test)] |
| 485 | +mod type_extractor_tests { |
| 486 | + use super::*; |
| 487 | + |
| 488 | + #[test] |
| 489 | + fn test_type_extractor_creation() { |
| 490 | + let config = TypeExtractorConfig::default(); |
| 491 | + let extractor = TypeExtractor::new(Language::Java, config); |
| 492 | + |
| 493 | + // Basic smoke test |
| 494 | + assert!(true); |
| 495 | + } |
| 496 | + |
| 497 | + #[test] |
| 498 | + fn test_java_type_parsing() { |
| 499 | + let extractor = TypeExtractor::with_defaults(Language::Java); |
| 500 | + |
| 501 | + // Test simple type |
| 502 | + let simple_type = extractor.parse_type_signature("String").unwrap(); |
| 503 | + assert_eq!(simple_type.base_type, "String"); |
| 504 | + |
| 505 | + // Test generic type |
| 506 | + let generic_type = extractor.parse_type_signature("List<String>").unwrap(); |
| 507 | + assert_eq!(generic_type.base_type, "List"); |
| 508 | + assert_eq!(generic_type.generic_params.len(), 1); |
| 509 | + assert_eq!(generic_type.generic_params[0].base_type, "String"); |
| 510 | + } |
| 511 | + |
| 512 | + #[test] |
| 513 | + fn test_python_type_parsing() { |
| 514 | + let extractor = TypeExtractor::with_defaults(Language::Python); |
| 515 | + |
| 516 | + // Test Python list type |
| 517 | + let list_type = extractor.parse_type_signature("List[str]").unwrap(); |
| 518 | + assert_eq!(list_type.base_type, "List"); |
| 519 | + assert_eq!(list_type.generic_params.len(), 1); |
| 520 | + assert_eq!(list_type.generic_params[0].base_type, "str"); |
| 521 | + |
| 522 | + // Test Python dict type |
| 523 | + let dict_type = extractor.parse_type_signature("Dict[str, int]").unwrap(); |
| 524 | + assert_eq!(dict_type.base_type, "Dict"); |
| 525 | + assert_eq!(dict_type.generic_params.len(), 2); |
| 526 | + assert_eq!(dict_type.generic_params[0].base_type, "str"); |
| 527 | + assert_eq!(dict_type.generic_params[1].base_type, "int"); |
| 528 | + } |
| 529 | + |
| 530 | + #[test] |
| 531 | + fn test_cpp_type_parsing() { |
| 532 | + let extractor = TypeExtractor::with_defaults(Language::Cpp); |
| 533 | + |
| 534 | + // Test const pointer type |
| 535 | + let const_ptr_type = extractor.parse_type_signature("const int*").unwrap(); |
| 536 | + assert_eq!(const_ptr_type.base_type, "const int*"); |
| 537 | + assert!(const_ptr_type.modifiers.contains(&"const".to_string())); |
| 538 | + assert!(const_ptr_type.modifiers.contains(&"pointer".to_string())); |
| 539 | + |
| 540 | + // Test reference type |
| 541 | + let ref_type = extractor.parse_type_signature("std::string&").unwrap(); |
| 542 | + assert!(ref_type.modifiers.contains(&"reference".to_string())); |
| 543 | + } |
| 544 | + |
| 545 | + #[test] |
| 546 | + fn test_primitive_type_detection() { |
| 547 | + let extractor = TypeExtractor::with_defaults(Language::Java); |
| 548 | + |
| 549 | + assert!(extractor.is_primitive_type("int")); |
| 550 | + assert!(extractor.is_primitive_type("String")); |
| 551 | + assert!(extractor.is_primitive_type("boolean")); |
| 552 | + assert!(extractor.is_primitive_type("void")); |
| 553 | + |
| 554 | + assert!(!extractor.is_primitive_type("ArrayList")); |
| 555 | + assert!(!extractor.is_primitive_type("MyCustomClass")); |
| 556 | + } |
| 557 | + |
| 558 | + #[test] |
| 559 | + fn test_type_dependency_graph_building() { |
| 560 | + let extractor = TypeExtractor::with_defaults(Language::Java); |
| 561 | + |
| 562 | + // Create mock extracted type info |
| 563 | + let mut extracted_types = Vec::new(); |
| 564 | + |
| 565 | + // This would normally come from actual type extraction |
| 566 | + // For now, just test that the method doesn't panic |
| 567 | + let dependencies = extractor.build_type_dependency_graph(&extracted_types); |
| 568 | + assert!(dependencies.is_empty()); |
| 569 | + } |
| 570 | +} |
| 571 | + |
| 572 | +#[cfg(test)] |
| 573 | +mod type_dependency_graph_tests { |
| 574 | + use super::*; |
| 575 | + |
| 576 | + #[test] |
| 577 | + fn test_type_dependency_graph_creation() { |
| 578 | + let mut builder = TypeDependencyGraphBuilder::new(); |
| 579 | + |
| 580 | + // Basic smoke test |
| 581 | + assert_eq!(builder.get_type_info_map().len(), 0); |
| 582 | + } |
| 583 | + |
| 584 | + #[test] |
| 585 | + fn test_type_relationship_types() { |
| 586 | + // Test that all relationship types are properly defined |
| 587 | + let inheritance = TypeRelationshipType::Inheritance; |
| 588 | + let implementation = TypeRelationshipType::Implementation; |
| 589 | + let composition = TypeRelationshipType::Composition; |
| 590 | + |
| 591 | + assert_ne!(inheritance, implementation); |
| 592 | + assert_ne!(implementation, composition); |
| 593 | + assert_ne!(composition, inheritance); |
| 594 | + } |
| 595 | + |
| 596 | + #[test] |
| 597 | + fn test_coupling_metrics_calculation() { |
| 598 | + // This would test the coupling metrics calculation |
| 599 | + // For now, just ensure the types are properly defined |
| 600 | + use crate::TypeCouplingMetrics; |
| 601 | + |
| 602 | + let metrics = TypeCouplingMetrics { |
| 603 | + afferent_coupling: 5, |
| 604 | + efferent_coupling: 3, |
| 605 | + instability: 0.375, // 3 / (5 + 3) |
| 606 | + abstractness: 0.0, |
| 607 | + }; |
| 608 | + |
| 609 | + assert_eq!(metrics.afferent_coupling, 5); |
| 610 | + assert_eq!(metrics.efferent_coupling, 3); |
| 611 | + assert!((metrics.instability - 0.375).abs() < 0.001); |
| 612 | + } |
| 613 | +} |
0 commit comments