@@ -917,6 +917,10 @@ impl Default for PlatformTestConfig {
917917#[ cfg( test) ]
918918mod tests {
919919 use super :: FromEnv ;
920+ use crate :: config:: {
921+ ChainLockConfig , ConsensusCoreRpcConfig , CoreConfig , InstantLockConfig , PlatformConfig ,
922+ QuorumLikeConfig , ValidatorSetConfig ,
923+ } ;
920924 use crate :: logging:: LogDestination ;
921925 use dpp:: dashcore:: Network ;
922926 use dpp:: dashcore_rpc:: dashcore_rpc_json:: QuorumType ;
@@ -969,4 +973,265 @@ mod tests {
969973 assert_eq ! ( config. network, config. drive. network) ;
970974 assert_eq ! ( config. network, Network :: Testnet ) ;
971975 }
976+
977+ // --- `from_str_to_network_with_aliases`: valid aliases and error path ---
978+
979+ /// Ensures every network alias accepted by the deserializer maps to the
980+ /// expected `Network`, case-insensitively. This exercises each match arm in
981+ /// `from_str_to_network_with_aliases`, which is otherwise only called at
982+ /// most once per integration-test setup.
983+ #[ test]
984+ fn network_aliases_deserialize_all_variants_case_insensitively ( ) {
985+ let cases = & [
986+ ( "\" dash\" " , Network :: Mainnet ) ,
987+ ( "\" DASH\" " , Network :: Mainnet ) ,
988+ ( "\" MainNet\" " , Network :: Mainnet ) ,
989+ ( "\" main\" " , Network :: Mainnet ) ,
990+ ( "\" local\" " , Network :: Regtest ) ,
991+ ( "\" regtest\" " , Network :: Regtest ) ,
992+ ( "\" testnet\" " , Network :: Testnet ) ,
993+ ( "\" TEST\" " , Network :: Testnet ) ,
994+ ( "\" devnet\" " , Network :: Devnet ) ,
995+ ( "\" Dev\" " , Network :: Devnet ) ,
996+ ] ;
997+
998+ for ( input, expected) in cases {
999+ let mut de = serde_json:: Deserializer :: from_str ( input) ;
1000+ let network = super :: from_str_to_network_with_aliases ( & mut de)
1001+ . expect ( "alias should parse successfully" ) ;
1002+ assert_eq ! (
1003+ & network, expected,
1004+ "input {} should map to {:?}" ,
1005+ input, expected
1006+ ) ;
1007+ }
1008+ }
1009+
1010+ /// Verifies that an unknown network alias produces a clear deserializer error.
1011+ /// This covers the final arm of `from_str_to_network_with_aliases`.
1012+ #[ test]
1013+ fn network_alias_unknown_value_returns_custom_error ( ) {
1014+ let mut de = serde_json:: Deserializer :: from_str ( "\" nonsense_network\" " ) ;
1015+ let err = super :: from_str_to_network_with_aliases ( & mut de)
1016+ . expect_err ( "unknown network should fail" ) ;
1017+ let msg = err. to_string ( ) ;
1018+ assert ! (
1019+ msg. contains( "unknown network" ) && msg. contains( "nonsense_network" ) ,
1020+ "error message should name the offending value, got: {}" ,
1021+ msg
1022+ ) ;
1023+ }
1024+
1025+ // --- `deserialize_quorum_type`: numeric/string/UNKNOWN error path ---
1026+
1027+ /// Covers the string-name branch of `deserialize_quorum_type`.
1028+ #[ test]
1029+ fn deserialize_quorum_type_accepts_string_names ( ) {
1030+ // All numeric fields use `from_str_or_number`, which requires a JSON
1031+ // string (even for numbers).
1032+ let json = r#"{
1033+ "validator_set_quorum_type": "llmq_25_67",
1034+ "validator_set_quorum_size": "25",
1035+ "validator_set_quorum_window": "24",
1036+ "validator_set_quorum_active_signers": "24",
1037+ "validator_set_quorum_rotation": "false"
1038+ }"# ;
1039+ let cfg: ValidatorSetConfig =
1040+ serde_json:: from_str ( json) . expect ( "quorum type string should deserialize" ) ;
1041+ assert_eq ! ( cfg. quorum_type, QuorumType :: Llmq25_67 ) ;
1042+ }
1043+
1044+ /// Covers the numeric (u32) branch of `deserialize_quorum_type` (a number
1045+ /// serialized as a JSON string still goes through the `parse::<u32>()` path).
1046+ #[ test]
1047+ fn deserialize_quorum_type_accepts_numeric_string ( ) {
1048+ let json = r#"{
1049+ "validator_set_quorum_type": "6",
1050+ "validator_set_quorum_size": "25",
1051+ "validator_set_quorum_window": "24",
1052+ "validator_set_quorum_active_signers": "24",
1053+ "validator_set_quorum_rotation": "false"
1054+ }"# ;
1055+ let cfg: ValidatorSetConfig =
1056+ serde_json:: from_str ( json) . expect ( "numeric quorum type should deserialize" ) ;
1057+ // QuorumType::from(6) should be a known variant; we only assert it is not UNKNOWN.
1058+ assert_ne ! ( cfg. quorum_type, QuorumType :: UNKNOWN ) ;
1059+ }
1060+
1061+ /// Covers the `UNKNOWN` rejection branch of `deserialize_quorum_type`.
1062+ #[ test]
1063+ fn deserialize_quorum_type_rejects_unknown_names ( ) {
1064+ let json = r#"{
1065+ "validator_set_quorum_type": "this_is_not_a_quorum",
1066+ "validator_set_quorum_size": "25",
1067+ "validator_set_quorum_window": "24",
1068+ "validator_set_quorum_active_signers": "24",
1069+ "validator_set_quorum_rotation": "false"
1070+ }"# ;
1071+ let err = serde_json:: from_str :: < ValidatorSetConfig > ( json)
1072+ . expect_err ( "unknown quorum type name should fail" ) ;
1073+ let msg = err. to_string ( ) ;
1074+ assert ! (
1075+ msg. contains( "unsupported" ) && msg. contains( "QUORUM_TYPE" ) ,
1076+ "expected unsupported QUORUM_TYPE error, got: {}" ,
1077+ msg
1078+ ) ;
1079+ }
1080+
1081+ // --- Core RPC URL composition and defaults ---
1082+
1083+ /// Exercises `ConsensusCoreRpcConfig::url` formatting.
1084+ #[ test]
1085+ fn consensus_core_rpc_url_composes_host_and_port ( ) {
1086+ let cfg = ConsensusCoreRpcConfig {
1087+ host : "node.example" . to_string ( ) ,
1088+ port : 9998 ,
1089+ username : "u" . to_string ( ) ,
1090+ password : "p" . to_string ( ) ,
1091+ } ;
1092+ assert_eq ! ( cfg. url( ) , "node.example:9998" ) ;
1093+ }
1094+
1095+ /// Exercises `CheckTxCoreRpcConfig::url` formatting.
1096+ #[ test]
1097+ fn check_tx_core_rpc_url_composes_host_and_port ( ) {
1098+ let cfg = super :: CheckTxCoreRpcConfig {
1099+ host : "127.0.0.1" . to_string ( ) ,
1100+ port : 1 ,
1101+ username : String :: new ( ) ,
1102+ password : String :: new ( ) ,
1103+ } ;
1104+ assert_eq ! ( cfg. url( ) , "127.0.0.1:1" ) ;
1105+ }
1106+
1107+ /// `CoreConfig::default()` should be empty strings and zero port (covers
1108+ /// the auto-derived `Default` with both flattened members).
1109+ #[ test]
1110+ fn core_config_default_is_empty ( ) {
1111+ let cfg = CoreConfig :: default ( ) ;
1112+ assert_eq ! ( cfg. consensus_rpc. host, "" ) ;
1113+ assert_eq ! ( cfg. consensus_rpc. port, 0 ) ;
1114+ assert_eq ! ( cfg. check_tx_rpc. host, "" ) ;
1115+ assert_eq ! ( cfg. check_tx_rpc. port, 0 ) ;
1116+ }
1117+
1118+ // --- `default_for_network` dispatch, including the catch-all ---
1119+
1120+ /// Exercises the `Network::Mainnet`, `Network::Testnet`, `Network::Devnet`,
1121+ /// `Network::Regtest` arms of `default_for_network`.
1122+ #[ test]
1123+ fn default_for_network_dispatches_all_known_networks ( ) {
1124+ let mainnet = PlatformConfig :: default_for_network ( Network :: Mainnet ) ;
1125+ assert_eq ! ( mainnet. network, Network :: Mainnet ) ;
1126+ assert_eq ! ( mainnet. validator_set. quorum_type, QuorumType :: Llmq100_67 ) ;
1127+
1128+ let testnet = PlatformConfig :: default_for_network ( Network :: Testnet ) ;
1129+ assert_eq ! ( testnet. network, Network :: Testnet ) ;
1130+ assert_eq ! ( testnet. validator_set. quorum_type, QuorumType :: Llmq25_67 ) ;
1131+
1132+ let devnet = PlatformConfig :: default_for_network ( Network :: Devnet ) ;
1133+ // default_devnet currently sets network to Regtest (see impl).
1134+ assert_eq ! ( devnet. network, Network :: Regtest ) ;
1135+
1136+ let regtest = PlatformConfig :: default_for_network ( Network :: Regtest ) ;
1137+ assert_eq ! ( regtest. network, Network :: Regtest ) ;
1138+ }
1139+
1140+ // --- `ValidatorSetConfig::default_100_67` and QuorumLikeConfig getters ---
1141+
1142+ /// Exercises `default_100_67` + every getter in `QuorumLikeConfig` for
1143+ /// `ValidatorSetConfig` - these getters are pure accessors that would
1144+ /// otherwise be uncovered outside the actual consensus path.
1145+ #[ test]
1146+ fn validator_set_default_100_67_accessors ( ) {
1147+ let cfg = ValidatorSetConfig :: default_100_67 ( ) ;
1148+ assert_eq ! ( cfg. quorum_type( ) , QuorumType :: Llmq100_67 ) ;
1149+ assert_eq ! ( cfg. quorum_size( ) , 100 ) ;
1150+ assert_eq ! ( cfg. quorum_window( ) , 24 ) ;
1151+ assert_eq ! ( cfg. quorum_active_signers( ) , 24 ) ;
1152+ assert ! ( !cfg. quorum_rotation( ) ) ;
1153+ }
1154+
1155+ /// Same but for `ChainLockConfig::default_100_67`.
1156+ #[ test]
1157+ fn chain_lock_default_100_67_accessors ( ) {
1158+ let cfg = ChainLockConfig :: default_100_67 ( ) ;
1159+ assert_eq ! ( cfg. quorum_type( ) , QuorumType :: Llmq100_67 ) ;
1160+ assert_eq ! ( cfg. quorum_size( ) , 100 ) ;
1161+ assert_eq ! ( cfg. quorum_window( ) , 24 ) ;
1162+ assert_eq ! ( cfg. quorum_active_signers( ) , 24 ) ;
1163+ assert ! ( !cfg. quorum_rotation( ) ) ;
1164+ }
1165+
1166+ /// `ChainLockConfig::default()` is Mainnet LLMQ400_60 - cover all getters.
1167+ #[ test]
1168+ fn chain_lock_default_is_llmq_400_60 ( ) {
1169+ let cfg = ChainLockConfig :: default ( ) ;
1170+ assert_eq ! ( cfg. quorum_type( ) , QuorumType :: Llmq400_60 ) ;
1171+ assert_eq ! ( cfg. quorum_size( ) , 400 ) ;
1172+ assert_eq ! ( cfg. quorum_window( ) , 24 * 12 ) ;
1173+ assert_eq ! ( cfg. quorum_active_signers( ) , 4 ) ;
1174+ assert ! ( !cfg. quorum_rotation( ) ) ;
1175+ }
1176+
1177+ /// `InstantLockConfig::default()` is DIP24 rotated LLMQ60_75.
1178+ #[ test]
1179+ fn instant_lock_default_is_llmq_60_75_rotated ( ) {
1180+ let cfg = InstantLockConfig :: default ( ) ;
1181+ assert_eq ! ( cfg. quorum_type( ) , QuorumType :: Llmq60_75 ) ;
1182+ assert_eq ! ( cfg. quorum_size( ) , 60 ) ;
1183+ assert_eq ! ( cfg. quorum_window( ) , 24 * 12 ) ;
1184+ assert_eq ! ( cfg. quorum_active_signers( ) , 32 ) ;
1185+ assert ! ( cfg. quorum_rotation( ) ) ;
1186+ }
1187+
1188+ /// `InstantLockConfig::default_100_67` is the classic LLMQ variant.
1189+ #[ test]
1190+ fn instant_lock_default_100_67_accessors ( ) {
1191+ let cfg = InstantLockConfig :: default_100_67 ( ) ;
1192+ assert_eq ! ( cfg. quorum_type( ) , QuorumType :: Llmq100_67 ) ;
1193+ assert_eq ! ( cfg. quorum_size( ) , 100 ) ;
1194+ assert_eq ! ( cfg. quorum_window( ) , 24 ) ;
1195+ assert_eq ! ( cfg. quorum_active_signers( ) , 24 ) ;
1196+ assert ! ( !cfg. quorum_rotation( ) ) ;
1197+ }
1198+
1199+ /// Exercises `PlatformConfig::default()` which delegates to `default_mainnet`.
1200+ #[ test]
1201+ fn platform_config_default_is_mainnet ( ) {
1202+ let cfg = PlatformConfig :: default ( ) ;
1203+ assert_eq ! ( cfg. network, Network :: Mainnet ) ;
1204+ assert_eq ! ( cfg. validator_set. quorum_type, QuorumType :: Llmq100_67 ) ;
1205+ assert_eq ! ( cfg. chain_lock. quorum_type, QuorumType :: Llmq400_60 ) ;
1206+ assert_eq ! ( cfg. instant_lock. quorum_type, QuorumType :: Llmq60_75 ) ;
1207+ assert_eq ! ( cfg. block_spacing_ms, 5000 ) ;
1208+ }
1209+
1210+ // --- `ExecutionConfig` default values ---
1211+
1212+ /// Exercises all four default-provider functions on `ExecutionConfig`.
1213+ #[ test]
1214+ fn execution_config_defaults ( ) {
1215+ let cfg = super :: ExecutionConfig :: default ( ) ;
1216+ assert ! ( cfg. verify_sum_trees) ;
1217+ assert ! ( cfg. verify_token_sum_trees) ;
1218+ assert ! ( cfg. use_document_triggers) ;
1219+ assert_eq ! ( cfg. epoch_time_length_s, 788400 ) ;
1220+ }
1221+
1222+ // --- `serialize_quorum_type` round-trip via Serialize ---
1223+
1224+ /// Covers the `serialize_quorum_type` codepath (symmetric pair of the
1225+ /// deserialize tests above).
1226+ #[ test]
1227+ fn validator_set_config_serializes_quorum_type_as_string ( ) {
1228+ let cfg = ValidatorSetConfig :: default_100_67 ( ) ;
1229+ let json = serde_json:: to_string ( & cfg) . expect ( "valid serialize" ) ;
1230+ // The serialized representation must use the textual form.
1231+ assert ! (
1232+ json. contains( "llmq_100_67" ) || json. contains( "Llmq100_67" ) ,
1233+ "expected textual quorum type in JSON, got: {}" ,
1234+ json
1235+ ) ;
1236+ }
9721237}
0 commit comments