@@ -842,3 +842,82 @@ pub async fn handle_graph_get_node(client: &LdkServerClient, args: Value) -> Res
842842 . map_err ( |e| e. message . clone ( ) ) ?;
843843 serde_json:: to_value ( response) . map_err ( |e| format ! ( "Failed to serialize response: {e}" ) )
844844}
845+
846+ #[ cfg( test) ]
847+ mod tests {
848+ use super :: {
849+ build_bolt11_invoice_description, build_channel_config, build_update_channel_config,
850+ parse_page_token,
851+ } ;
852+ use ldk_server_client:: ldk_server_grpc:: types:: bolt11_invoice_description;
853+ use serde_json:: json;
854+
855+ #[ test]
856+ fn parse_page_token_rejects_invalid_formats ( ) {
857+ assert_eq ! (
858+ parse_page_token( "missing-colon" ) . unwrap_err( ) ,
859+ "Page token must be in format 'token:index'"
860+ ) ;
861+ assert_eq ! ( parse_page_token( "token:not-a-number" ) . unwrap_err( ) , "Invalid page token index" ) ;
862+ }
863+
864+ #[ test]
865+ fn build_bolt11_invoice_description_rejects_conflicting_fields ( ) {
866+ let err = build_bolt11_invoice_description ( & json ! ( {
867+ "description" : "desc" ,
868+ "description_hash" : "hash"
869+ } ) )
870+ . unwrap_err ( ) ;
871+
872+ assert_eq ! ( err, "Only one of description or description_hash can be set" ) ;
873+ }
874+
875+ #[ test]
876+ fn build_bolt11_invoice_description_supports_direct_and_hash_modes ( ) {
877+ let direct =
878+ build_bolt11_invoice_description ( & json ! ( { "description" : "desc" } ) ) . unwrap ( ) . unwrap ( ) ;
879+ assert ! ( matches!(
880+ direct. kind,
881+ Some ( bolt11_invoice_description:: Kind :: Direct ( ref value) ) if value == "desc"
882+ ) ) ;
883+
884+ let hash = build_bolt11_invoice_description ( & json ! ( { "description_hash" : "hash" } ) )
885+ . unwrap ( )
886+ . unwrap ( ) ;
887+ assert ! ( matches!(
888+ hash. kind,
889+ Some ( bolt11_invoice_description:: Kind :: Hash ( ref value) ) if value == "hash"
890+ ) ) ;
891+ }
892+
893+ #[ test]
894+ fn build_channel_config_rejects_conflicting_dust_exposure_modes ( ) {
895+ let err = build_channel_config ( & json ! ( {
896+ "max_dust_htlc_exposure_fixed_limit_msat" : 1 ,
897+ "max_dust_htlc_exposure_fee_rate_multiplier" : 2
898+ } ) )
899+ . unwrap_err ( ) ;
900+
901+ assert_eq ! (
902+ err,
903+ "Only one of max_dust_htlc_exposure_fixed_limit_msat or max_dust_htlc_exposure_fee_rate_multiplier can be set"
904+ ) ;
905+ }
906+
907+ #[ test]
908+ fn build_channel_config_returns_none_when_no_fields_are_set ( ) {
909+ assert ! ( build_channel_config( & json!( { } ) ) . unwrap( ) . is_none( ) ) ;
910+ }
911+
912+ #[ test]
913+ fn build_update_channel_config_defaults_to_empty_config ( ) {
914+ let channel_config = build_update_channel_config ( & json ! ( { } ) ) . unwrap ( ) ;
915+
916+ assert_eq ! ( channel_config. forwarding_fee_proportional_millionths, None ) ;
917+ assert_eq ! ( channel_config. forwarding_fee_base_msat, None ) ;
918+ assert_eq ! ( channel_config. cltv_expiry_delta, None ) ;
919+ assert_eq ! ( channel_config. force_close_avoidance_max_fee_satoshis, None ) ;
920+ assert_eq ! ( channel_config. accept_underpaying_htlcs, None ) ;
921+ assert_eq ! ( channel_config. max_dust_htlc_exposure, None ) ;
922+ }
923+ }
0 commit comments