@@ -759,11 +759,135 @@ mod stellar_node_spec_validation {
759759 #[ test]
760760 fn test_validator_custom_network_passes ( ) {
761761 let mut spec = valid_validator_spec ( ) ;
762- spec. network = StellarNetwork :: Custom ;
763- spec. custom_network_passphrase = Some ( "My Private Network" . to_string ( ) ) ;
762+ spec. network = StellarNetwork :: Custom ( "my-private-network" . to_string ( ) ) ;
764763 assert ! ( spec. validate( ) . is_ok( ) ) ;
765764 }
766765
766+ // =========================================================================
767+ // Custom Network Name Validation Tests (#366)
768+ // =========================================================================
769+
770+ #[ test]
771+ fn test_custom_network_valid_alphanumeric_passes ( ) {
772+ let mut spec = valid_validator_spec ( ) ;
773+ spec. network = StellarNetwork :: Custom ( "my-private-net" . to_string ( ) ) ;
774+ assert ! ( spec. validate( ) . is_ok( ) ) ;
775+ }
776+
777+ #[ test]
778+ fn test_custom_network_single_char_passes ( ) {
779+ let mut spec = valid_validator_spec ( ) ;
780+ spec. network = StellarNetwork :: Custom ( "a" . to_string ( ) ) ;
781+ assert ! ( spec. validate( ) . is_ok( ) ) ;
782+ }
783+
784+ #[ test]
785+ fn test_custom_network_63_chars_passes ( ) {
786+ let mut spec = valid_validator_spec ( ) ;
787+ spec. network = StellarNetwork :: Custom ( "a" . repeat ( 63 ) ) ;
788+ assert ! ( spec. validate( ) . is_ok( ) ) ;
789+ }
790+
791+ #[ test]
792+ fn test_custom_network_empty_fails ( ) {
793+ let mut spec = valid_validator_spec ( ) ;
794+ spec. network = StellarNetwork :: Custom ( "" . to_string ( ) ) ;
795+ let result = spec. validate ( ) ;
796+ assert ! ( result. is_err( ) ) ;
797+ let errors = result. unwrap_err ( ) ;
798+ assert ! ( errors
799+ . iter( )
800+ . any( |e| e. field == "spec.network.customName" && e. message. contains( "empty" ) ) ) ;
801+ }
802+
803+ #[ test]
804+ fn test_custom_network_exceeds_63_chars_fails ( ) {
805+ let mut spec = valid_validator_spec ( ) ;
806+ spec. network = StellarNetwork :: Custom ( "a" . repeat ( 64 ) ) ;
807+ let result = spec. validate ( ) ;
808+ assert ! ( result. is_err( ) ) ;
809+ let errors = result. unwrap_err ( ) ;
810+ assert ! ( errors
811+ . iter( )
812+ . any( |e| e. field == "spec.network.customName" && e. message. contains( "63" ) ) ) ;
813+ }
814+
815+ #[ test]
816+ fn test_custom_network_special_chars_fails ( ) {
817+ for bad in & [ "; drop table" , "my@network" , "net$name!" , "net name" ] {
818+ let mut spec = valid_validator_spec ( ) ;
819+ spec. network = StellarNetwork :: Custom ( bad. to_string ( ) ) ;
820+ let result = spec. validate ( ) ;
821+ assert ! (
822+ result. is_err( ) ,
823+ "Expected validation failure for customName: '{bad}'"
824+ ) ;
825+ let errors = result. unwrap_err ( ) ;
826+ assert ! (
827+ errors. iter( ) . any( |e| e. field == "spec.network.customName" ) ,
828+ "Expected spec.network.customName error for '{bad}'"
829+ ) ;
830+ }
831+ }
832+
833+ #[ test]
834+ fn test_custom_network_leading_hyphen_fails ( ) {
835+ let mut spec = valid_validator_spec ( ) ;
836+ spec. network = StellarNetwork :: Custom ( "-bad-name" . to_string ( ) ) ;
837+ let result = spec. validate ( ) ;
838+ assert ! ( result. is_err( ) ) ;
839+ assert ! ( result
840+ . unwrap_err( )
841+ . iter( )
842+ . any( |e| e. field == "spec.network.customName" ) ) ;
843+ }
844+
845+ #[ test]
846+ fn test_custom_network_trailing_hyphen_fails ( ) {
847+ let mut spec = valid_validator_spec ( ) ;
848+ spec. network = StellarNetwork :: Custom ( "bad-name-" . to_string ( ) ) ;
849+ let result = spec. validate ( ) ;
850+ assert ! ( result. is_err( ) ) ;
851+ assert ! ( result
852+ . unwrap_err( )
853+ . iter( )
854+ . any( |e| e. field == "spec.network.customName" ) ) ;
855+ }
856+
857+ #[ test]
858+ fn test_non_custom_networks_skip_name_validation ( ) {
859+ for network in [
860+ StellarNetwork :: Mainnet ,
861+ StellarNetwork :: Testnet ,
862+ StellarNetwork :: Futurenet ,
863+ ] {
864+ let mut spec = valid_validator_spec ( ) ;
865+ spec. network = network;
866+ assert ! ( spec. validate( ) . is_ok( ) ) ;
867+ }
868+ }
869+
870+ #[ test]
871+ fn test_custom_network_uppercase_fails ( ) {
872+ // DNS-1123 requires lowercase; uppercase must be rejected
873+ for bad in & [ "MyNetwork" , "My-Net" , "MYNET" ] {
874+ let mut spec = valid_validator_spec ( ) ;
875+ spec. network = StellarNetwork :: Custom ( bad. to_string ( ) ) ;
876+ let result = spec. validate ( ) ;
877+ assert ! (
878+ result. is_err( ) ,
879+ "Expected validation failure for uppercase customName: '{bad}'"
880+ ) ;
881+ assert ! (
882+ result
883+ . unwrap_err( )
884+ . iter( )
885+ . any( |e| e. field == "spec.network.customName" ) ,
886+ "Expected spec.network.customName error for '{bad}'"
887+ ) ;
888+ }
889+ }
890+
767891 // =========================================================================
768892 // Edge Cases and Boundary Tests
769893 // =========================================================================
0 commit comments