@@ -880,6 +880,119 @@ else
880880fi
881881fi
882882
883+ # --- Test 23: $-prefix wildcard guard [MQTT-4.7.2] ---
884+ echo " "
885+ echo " --- Test 23: \$ -prefix wildcard guard [MQTT-4.7.2] ---"
886+ if [ " $skip_plain " = " yes" ]; then
887+ echo " SKIP: \$ -prefix wildcard guard (plain listener disabled)"
888+ elif [ " $has_wildcards " = " no" ]; then
889+ echo " SKIP: \$ -prefix wildcard guard (wildcards not built)"
890+ else
891+ start_broker
892+ # Subscribe to '#' (should NOT receive $SYS messages per MQTT-4.7.2)
893+ rm -f " ${TMP_DIR} /t23_wild.ready" " ${TMP_DIR} /t23_exact.ready"
894+ timeout 10 ./$sub_bin -T -h 127.0.0.1 -p $port -n " #" -i " sub_wild_dollar" \
895+ -R " ${TMP_DIR} /t23_wild.ready" > " ${TMP_DIR} /t23_wild.log" 2>&1 &
896+ T23_WILD_PID=$!
897+ # Subscribe to exact '$SYS/test' (SHOULD receive the message)
898+ timeout 10 ./$sub_bin -T -h 127.0.0.1 -p $port -n ' $SYS/test' -i " sub_exact_dollar" \
899+ -R " ${TMP_DIR} /t23_exact.ready" > " ${TMP_DIR} /t23_exact.log" 2>&1 &
900+ T23_EXACT_PID=$!
901+ TEST_PIDS+=($T23_WILD_PID $T23_EXACT_PID )
902+ wait_for_file " ${TMP_DIR} /t23_wild.ready" 5
903+ wait_for_file " ${TMP_DIR} /t23_exact.ready" 5
904+ # Publish to $SYS/test
905+ ./$pub_bin -T -h 127.0.0.1 -p $port -n ' $SYS/test' -m " dollar_sys_msg" \
906+ > " ${TMP_DIR} /t23_pub.log" 2>&1
907+ sleep 0.3
908+ kill $T23_WILD_PID $T23_EXACT_PID 2> /dev/null
909+ wait $T23_WILD_PID 2> /dev/null || true
910+ wait $T23_EXACT_PID 2> /dev/null || true
911+ TEST_PIDS=()
912+ T23_WILD_GOT=no
913+ T23_EXACT_GOT=no
914+ grep -q " dollar_sys_msg" " ${TMP_DIR} /t23_wild.log" 2> /dev/null && T23_WILD_GOT=yes
915+ grep -q " dollar_sys_msg" " ${TMP_DIR} /t23_exact.log" 2> /dev/null && T23_EXACT_GOT=yes
916+ if [ " $T23_WILD_GOT " = " no" ] && [ " $T23_EXACT_GOT " = " yes" ]; then
917+ echo " PASS: \$ -prefix wildcard guard (# blocked, exact matched)"
918+ else
919+ echo " FAIL: \$ -prefix wildcard guard (wild_got=$T23_WILD_GOT , exact_got=$T23_EXACT_GOT )"
920+ FAIL=1
921+ fi
922+ fi
923+
924+ # --- Test 24: PUBLISH topic wildcard rejection [MQTT-3.3.2-2] ---
925+ echo " "
926+ echo " --- Test 24: PUBLISH topic wildcard rejection [MQTT-3.3.2-2] ---"
927+ if [ " $skip_plain " = " yes" ]; then
928+ echo " SKIP: PUBLISH wildcard rejection (plain listener disabled)"
929+ elif [ " $has_wildcards " = " no" ]; then
930+ echo " SKIP: PUBLISH wildcard rejection (wildcards not built)"
931+ else
932+ start_broker
933+ # Subscribe to a wildcard filter that would match if the broker allowed it
934+ rm -f " ${TMP_DIR} /t24_sub.ready"
935+ timeout 10 ./$sub_bin -T -h 127.0.0.1 -p $port -n " test/wild/+" -i " sub_wild24" \
936+ -R " ${TMP_DIR} /t24_sub.ready" > " ${TMP_DIR} /t24_sub.log" 2>&1 &
937+ T24_SUB_PID=$!
938+ TEST_PIDS+=($T24_SUB_PID )
939+ wait_for_file " ${TMP_DIR} /t24_sub.ready" 5
940+ # Attempt to PUBLISH with '+' in the topic name (must be rejected by broker)
941+ ./$pub_bin -T -h 127.0.0.1 -p $port -n " test/+/card" -m " bad_wildcard_plus" \
942+ > " ${TMP_DIR} /t24_pub_plus.log" 2>&1
943+ # Attempt to PUBLISH with '#' in the topic name (must be rejected by broker)
944+ ./$pub_bin -T -h 127.0.0.1 -p $port -n " test/#" -m " bad_wildcard_hash" \
945+ > " ${TMP_DIR} /t24_pub_hash.log" 2>&1
946+ sleep 0.3
947+ kill $T24_SUB_PID 2> /dev/null
948+ wait $T24_SUB_PID 2> /dev/null || true
949+ TEST_PIDS=()
950+ # Verify subscriber did NOT receive either message
951+ T24_GOT_PLUS=no
952+ T24_GOT_HASH=no
953+ grep -q " bad_wildcard_plus" " ${TMP_DIR} /t24_sub.log" 2> /dev/null && T24_GOT_PLUS=yes
954+ grep -q " bad_wildcard_hash" " ${TMP_DIR} /t24_sub.log" 2> /dev/null && T24_GOT_HASH=yes
955+ if [ " $T24_GOT_PLUS " = " no" ] && [ " $T24_GOT_HASH " = " no" ]; then
956+ echo " PASS: PUBLISH topic wildcard rejection (+ and # blocked)"
957+ else
958+ echo " FAIL: PUBLISH wildcard rejection (got_plus=$T24_GOT_PLUS , got_hash=$T24_GOT_HASH )"
959+ FAIL=1
960+ fi
961+ fi
962+
963+ # --- Test 25: Multi-level wildcard matches parent [MQTT-4.7.1.2] ---
964+ echo " "
965+ echo " --- Test 25: Multi-level wildcard matches parent [MQTT-4.7.1.2] ---"
966+ if [ " $skip_plain " = " yes" ]; then
967+ echo " SKIP: Multi-level wildcard parent match (plain listener disabled)"
968+ elif [ " $has_wildcards " = " no" ]; then
969+ echo " SKIP: Multi-level wildcard parent match (wildcards not built)"
970+ else
971+ start_broker
972+ # Subscribe to 'sport/#' — per MQTT-4.7.1.2 this must also match 'sport'
973+ rm -f " ${TMP_DIR} /t25_sub.ready"
974+ timeout 10 ./$sub_bin -T -h 127.0.0.1 -p $port -n " sport/#" -i " sub_parent25" \
975+ -R " ${TMP_DIR} /t25_sub.ready" > " ${TMP_DIR} /t25_sub.log" 2>&1 &
976+ T25_SUB_PID=$!
977+ TEST_PIDS+=($T25_SUB_PID )
978+ wait_for_file " ${TMP_DIR} /t25_sub.ready" 5
979+ # Publish to 'sport' (parent level, no trailing slash)
980+ ./$pub_bin -T -h 127.0.0.1 -p $port -n " sport" -m " parent_match_msg" \
981+ > " ${TMP_DIR} /t25_pub.log" 2>&1
982+ sleep 0.3
983+ kill $T25_SUB_PID 2> /dev/null
984+ wait $T25_SUB_PID 2> /dev/null || true
985+ TEST_PIDS=()
986+ T25_GOT=no
987+ grep -q " parent_match_msg" " ${TMP_DIR} /t25_sub.log" 2> /dev/null && T25_GOT=yes
988+ if [ " $T25_GOT " = " yes" ]; then
989+ echo " PASS: Multi-level wildcard matches parent (sport/# matched sport)"
990+ else
991+ echo " FAIL: Multi-level wildcard parent match (got=$T25_GOT )"
992+ FAIL=1
993+ fi
994+ fi
995+
883996# --- WebSocket Tests ---
884997ws_client_bin=" examples/websocket/websocket_client"
885998has_websocket=no
0 commit comments