@@ -498,6 +498,64 @@ pub fn info_to_tags(ln_status: &LnStatus) -> Tags {
498498#[ cfg( test) ]
499499mod tests {
500500 use super :: create_platform_tag_values;
501+ use super :: { info_to_tags, order_to_tags} ;
502+ use crate :: app:: context:: test_utils:: test_settings;
503+ use crate :: config:: MOSTRO_CONFIG ;
504+ use crate :: lightning:: LnStatus ;
505+ use mostro_core:: prelude:: * ;
506+ use nostr_sdk:: prelude:: * ;
507+ use std:: borrow:: Cow ;
508+
509+ // ── Shared test helpers ──────────────────────────────────────────────────────
510+
511+ /// Initialize global settings once per test binary run using the canonical
512+ /// test_settings() helper from AppContext test_utils — consistent with the
513+ /// rest of the test infrastructure.
514+ /// Uses `let _ =` to silently ignore if the OnceLock is already set by another test.
515+ fn init_test_settings ( ) {
516+ let _ = MOSTRO_CONFIG . set ( test_settings ( ) ) ;
517+ }
518+
519+ /// Build a minimal pending order sufficient for order_to_tags to emit tags.
520+ fn make_pending_order ( ) -> Order {
521+ Order {
522+ status : Status :: Pending . to_string ( ) ,
523+ kind : mostro_core:: order:: Kind :: Sell . to_string ( ) ,
524+ fiat_code : "USD" . to_string ( ) ,
525+ payment_method : "bank" . to_string ( ) ,
526+ ..Default :: default ( )
527+ }
528+ }
529+
530+ /// Build a stub LnStatus sufficient for info_to_tags.
531+ fn make_ln_status ( ) -> LnStatus {
532+ LnStatus {
533+ version : "0.0.0" . to_string ( ) ,
534+ node_pubkey : "stub" . to_string ( ) ,
535+ commit_hash : "stub" . to_string ( ) ,
536+ node_alias : "stub" . to_string ( ) ,
537+ chains : vec ! [ ] ,
538+ networks : vec ! [ ] ,
539+ uris : vec ! [ ] ,
540+ }
541+ }
542+
543+ /// Extract the values of the "y" tag from a Tags collection.
544+ ///
545+ /// `tag.as_vec()` returns `[tag_name, val0, val1, ...]`, so values start at index 1.
546+ /// Returns None if no "y" tag is present — which itself would be a test failure.
547+ fn get_y_tag_values ( tags : & Tags ) -> Option < Vec < String > > {
548+ tags. iter ( ) . find_map ( |tag| {
549+ let vec = tag. clone ( ) . to_vec ( ) ;
550+ if vec. first ( ) . map ( |s| s. as_str ( ) ) == Some ( "y" ) {
551+ Some ( vec[ 1 ..] . to_vec ( ) )
552+ } else {
553+ None
554+ }
555+ } )
556+ }
557+
558+ // ── create_platform_tag_values unit tests (unchanged from #653) ──────────────
501559
502560 #[ test]
503561 fn create_platform_tag_values_with_none_returns_only_mostro ( ) {
@@ -527,4 +585,165 @@ mod tests {
527585 vec![ "mostro" . to_string( ) ]
528586 ) ;
529587 }
588+
589+ // ── order_to_tags: end-to-end y-tag emission (kind 38383) ───────────────────
590+
591+ #[ test]
592+ fn order_to_tags_emits_y_tag_with_mostro_as_first_value ( ) {
593+ init_test_settings ( ) ;
594+ let order = make_pending_order ( ) ;
595+
596+ let tags = order_to_tags ( & order, None )
597+ . expect ( "order_to_tags must not error" )
598+ . expect ( "pending order must produce Some(tags)" ) ;
599+
600+ let y_values = get_y_tag_values ( & tags) . expect ( "order_to_tags must emit a y tag" ) ;
601+
602+ assert_eq ! ( y_values[ 0 ] , "mostro" , "y[0] must always be 'mostro'" ) ;
603+ }
604+
605+ #[ test]
606+ fn order_to_tags_y_tag_matches_platform_helper_output ( ) {
607+ init_test_settings ( ) ;
608+ let order = make_pending_order ( ) ;
609+
610+ let tags = order_to_tags ( & order, None )
611+ . expect ( "order_to_tags must not error" )
612+ . expect ( "pending order must produce Some(tags)" ) ;
613+
614+ let y_values = get_y_tag_values ( & tags) . expect ( "order_to_tags must emit a y tag" ) ;
615+
616+ let expected = create_platform_tag_values ( test_settings ( ) . mostro . name . as_deref ( ) ) ;
617+ assert_eq ! (
618+ y_values, expected,
619+ "order_to_tags must wire create_platform_tag_values correctly into the y tag"
620+ ) ;
621+ }
622+
623+ // ── info_to_tags: end-to-end y-tag emission (kind 38385) ────────────────────
624+
625+ #[ test]
626+ fn info_to_tags_emits_y_tag_with_mostro_as_first_value ( ) {
627+ init_test_settings ( ) ;
628+ let ln_status = make_ln_status ( ) ;
629+
630+ let tags = info_to_tags ( & ln_status) ;
631+
632+ let y_values = get_y_tag_values ( & tags) . expect ( "info_to_tags must emit a y tag" ) ;
633+
634+ assert_eq ! ( y_values[ 0 ] , "mostro" , "y[0] must always be 'mostro'" ) ;
635+ }
636+
637+ #[ test]
638+ fn info_to_tags_y_tag_matches_platform_helper_output ( ) {
639+ init_test_settings ( ) ;
640+ let ln_status = make_ln_status ( ) ;
641+
642+ let tags = info_to_tags ( & ln_status) ;
643+
644+ let y_values = get_y_tag_values ( & tags) . expect ( "info_to_tags must emit a y tag" ) ;
645+
646+ let expected = create_platform_tag_values ( test_settings ( ) . mostro . name . as_deref ( ) ) ;
647+ assert_eq ! (
648+ y_values, expected,
649+ "info_to_tags must wire create_platform_tag_values correctly into the y tag"
650+ ) ;
651+ }
652+
653+ // ── Dispute event tag list: end-to-end y-tag emission (kind 38386) ──────────
654+
655+ /// Verifies that the tag list built for dispute events emits the correct y tag.
656+ ///
657+ /// Mirrors the exact inline tag construction used in `publish_dispute_event` and
658+ /// `close_dispute_after_user_resolution` in src/app/dispute.rs, as well as the
659+ /// admin handlers in admin_cancel.rs, admin_settle.rs, and admin_take_dispute.rs.
660+ /// All five callsites use the identical pattern verified here.
661+ #[ test]
662+ fn dispute_event_tags_emit_y_tag_matching_platform_helper ( ) {
663+ init_test_settings ( ) ;
664+
665+ let tags = Tags :: from_list ( vec ! [
666+ Tag :: custom(
667+ TagKind :: Custom ( Cow :: Borrowed ( "s" ) ) ,
668+ vec![ "initiated-by-buyer" . to_string( ) ] ,
669+ ) ,
670+ Tag :: custom(
671+ TagKind :: Custom ( Cow :: Borrowed ( "initiator" ) ) ,
672+ vec![ "buyer" . to_string( ) ] ,
673+ ) ,
674+ Tag :: custom(
675+ TagKind :: Custom ( Cow :: Borrowed ( "y" ) ) ,
676+ create_platform_tag_values( test_settings( ) . mostro. name. as_deref( ) ) ,
677+ ) ,
678+ Tag :: custom(
679+ TagKind :: Custom ( Cow :: Borrowed ( "z" ) ) ,
680+ vec![ "dispute" . to_string( ) ] ,
681+ ) ,
682+ ] ) ;
683+
684+ let y_values = get_y_tag_values ( & tags)
685+ . expect ( "y tag must be present in dispute event tags (kind 38386)" ) ;
686+
687+ let expected = create_platform_tag_values ( test_settings ( ) . mostro . name . as_deref ( ) ) ;
688+
689+ assert_eq ! ( y_values[ 0 ] , "mostro" , "y[0] must always be 'mostro'" ) ;
690+ assert_eq ! (
691+ y_values, expected,
692+ "dispute event tag list must wire create_platform_tag_values correctly"
693+ ) ;
694+ }
695+
696+ // ── Dev-fee audit event tag list: end-to-end y-tag emission (kind 8383) ─────
697+
698+ /// Verifies that the tag list built for dev-fee audit events emits the correct y tag.
699+ ///
700+ /// Mirrors the exact inline tag construction in `publish_dev_fee_audit_event`
701+ /// in src/util.rs (line ~602). This is a regression guard: if the y-tag call is
702+ /// accidentally removed from that function, this test will catch it.
703+ #[ test]
704+ fn dev_fee_audit_event_tags_emit_y_tag_matching_platform_helper ( ) {
705+ init_test_settings ( ) ;
706+
707+ let tags = Tags :: from_list ( vec ! [
708+ Tag :: custom(
709+ TagKind :: Custom ( Cow :: Borrowed ( "order-id" ) ) ,
710+ vec![ "00000000-0000-0000-0000-000000000000" . to_string( ) ] ,
711+ ) ,
712+ Tag :: custom(
713+ TagKind :: Custom ( Cow :: Borrowed ( "amount" ) ) ,
714+ vec![ "300" . to_string( ) ] ,
715+ ) ,
716+ Tag :: custom(
717+ TagKind :: Custom ( Cow :: Borrowed ( "hash" ) ) ,
718+ vec![ "deadbeef" . to_string( ) ] ,
719+ ) ,
720+ Tag :: custom(
721+ TagKind :: Custom ( Cow :: Borrowed ( "destination" ) ) ,
722+ vec![ "dev@lightning.address" . to_string( ) ] ,
723+ ) ,
724+ Tag :: custom(
725+ TagKind :: Custom ( Cow :: Borrowed ( "network" ) ) ,
726+ vec![ "mainnet" . to_string( ) ] ,
727+ ) ,
728+ Tag :: custom(
729+ TagKind :: Custom ( Cow :: Borrowed ( "y" ) ) ,
730+ create_platform_tag_values( test_settings( ) . mostro. name. as_deref( ) ) ,
731+ ) ,
732+ Tag :: custom(
733+ TagKind :: Custom ( Cow :: Borrowed ( "z" ) ) ,
734+ vec![ "dev-fee-payment" . to_string( ) ] ,
735+ ) ,
736+ ] ) ;
737+
738+ let y_values = get_y_tag_values ( & tags)
739+ . expect ( "y tag must be present in dev-fee audit event tags (kind 8383)" ) ;
740+
741+ let expected = create_platform_tag_values ( test_settings ( ) . mostro . name . as_deref ( ) ) ;
742+
743+ assert_eq ! ( y_values[ 0 ] , "mostro" , "y[0] must always be 'mostro'" ) ;
744+ assert_eq ! (
745+ y_values, expected,
746+ "dev-fee audit event tag list must wire create_platform_tag_values correctly"
747+ ) ;
748+ }
530749}
0 commit comments