541 |
541 |
542 ctx->on_chan_join = true; |
542 ctx->on_chan_join = true; |
543 |
543 |
544 log_debug("on_join"); |
544 log_debug("on_join"); |
545 } |
545 } |
|
546 |
|
547 void _on_chan_part (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg) |
|
548 { |
|
549 struct test_chan_ctx *ctx = arg; |
|
550 |
|
551 assert(chan == ctx->chan); |
|
552 |
|
553 // XXX: verify source |
|
554 // XXX: verify msg |
|
555 |
|
556 ctx->on_chan_part = true; |
|
557 |
|
558 log_debug("on_part"); |
|
559 } |
|
560 |
546 |
561 |
547 struct irc_chan_callbacks _chan_callbacks = { |
562 struct irc_chan_callbacks _chan_callbacks = { |
548 .on_self_join = &_on_chan_self_join, |
563 .on_self_join = &_on_chan_self_join, |
549 .on_join = &_on_chan_join, |
564 .on_join = &_on_chan_join, |
|
565 .on_part = &_on_chan_part, |
550 }; |
566 }; |
551 |
567 |
552 /** |
568 /** |
553 * Setup an irc_net using the given socket, and consume the register request output, but do not push the RPL_WELCOME |
569 * Setup an irc_net using the given socket, and consume the register request output, but do not push the RPL_WELCOME |
554 */ |
570 */ |
622 // cleanup |
638 // cleanup |
623 irc_net_destroy(net); |
639 irc_net_destroy(net); |
624 } |
640 } |
625 |
641 |
626 /** |
642 /** |
|
643 * Ensure that an irc_chan_user exists/doesn't exist for the given channel/nickname, and return it |
|
644 */ |
|
645 struct irc_chan_user* check_chan_user (struct irc_chan *chan, const char *nickname, bool exists) |
|
646 { |
|
647 struct irc_chan_user *chan_user = irc_chan_get_user(chan, nickname); |
|
648 |
|
649 if (exists && chan_user == NULL) |
|
650 FATAL("user %s not found in channel %s", dump_str(nickname), dump_str(irc_chan_name(chan))); |
|
651 |
|
652 if (!exists && chan_user) |
|
653 FATAL("user %s should not be on channel %s anymore", dump_str(nickname), dump_str(irc_chan_name(chan))); |
|
654 |
|
655 log_debug("%s, exists=%d -> %p: user=%p, nickname=%s", |
|
656 nickname, exists, chan_user, chan_user ? chan_user->user : NULL, chan_user ? chan_user->user->nickname : NULL); |
|
657 |
|
658 if (chan_user) |
|
659 assert_strcmp(chan_user->user->nickname, nickname); |
|
660 |
|
661 return chan_user; |
|
662 } |
|
663 |
|
664 /** |
627 * Creates an irc_chan on the given irc_net, but does not check any output (useful for testing offline add). |
665 * Creates an irc_chan on the given irc_net, but does not check any output (useful for testing offline add). |
628 * |
666 * |
629 * You must pass a test_chan_ctx for use with later operations, this will be initialized for you. |
667 * You must pass a test_chan_ctx for use with later operations, this will be initialized for you. |
630 */ |
668 */ |
631 struct irc_chan* setup_irc_chan_raw (struct irc_net *net, struct test_chan_ctx *ctx) |
669 struct irc_chan* setup_irc_chan_raw (struct irc_net *net, struct test_chan_ctx *ctx) |
663 assert(!ctx->chan->joining && ctx->chan->joined); |
701 assert(!ctx->chan->joining && ctx->chan->joined); |
664 assert(ctx->on_chan_self_join); |
702 assert(ctx->on_chan_self_join); |
665 } |
703 } |
666 |
704 |
667 /** |
705 /** |
|
706 * Sends a short RPL_NAMREPLY/RPL_ENDOFNAMES reply and checks that the users list matches |
|
707 */ |
|
708 void do_irc_chan_namreply (struct sock_test *sock, struct test_chan_ctx *ctx) |
|
709 { |
|
710 // RPL_NAMREPLY |
|
711 test_sock_push(sock, "353 mynick = #test :mynick userA +userB @userC\r\n"); |
|
712 test_sock_push(sock, "366 mynick #test :End of NAMES\r\n"); |
|
713 |
|
714 // XXX: this should be an exclusive test, i.e. these should be the only ones... |
|
715 check_chan_user(ctx->chan, "mynick", true); |
|
716 check_chan_user(ctx->chan, "userA", true); |
|
717 check_chan_user(ctx->chan, "userB", true); |
|
718 check_chan_user(ctx->chan, "userC", true); |
|
719 } |
|
720 |
|
721 /** |
668 * Creates an irc_chan on the given irc_net, and checks up to the JOIN reply |
722 * Creates an irc_chan on the given irc_net, and checks up to the JOIN reply |
669 */ |
723 */ |
670 struct irc_chan* setup_irc_chan (struct sock_test *sock, struct irc_net *net, struct test_chan_ctx *ctx) |
724 struct irc_chan* setup_irc_chan_join (struct sock_test *sock, struct irc_net *net, struct test_chan_ctx *ctx) |
671 { |
725 { |
672 setup_irc_chan_raw(net, ctx); |
726 setup_irc_chan_raw(net, ctx); |
673 do_irc_chan_join(sock, ctx); |
727 do_irc_chan_join(sock, ctx); |
674 |
728 |
675 // ok |
729 // ok |
676 return ctx->chan; |
730 return ctx->chan; |
677 } |
731 } |
|
732 |
|
733 /** |
|
734 * Creates an irc_chan on the given irc_net, sends the JOIN stuff plus RPL_NAMREPLY |
|
735 */ |
|
736 struct irc_chan* setup_irc_chan (struct sock_test *sock, struct irc_net *net, struct test_chan_ctx *ctx) |
|
737 { |
|
738 setup_irc_chan_raw(net, ctx); |
|
739 do_irc_chan_join(sock, ctx); |
|
740 do_irc_chan_namreply(sock, ctx); |
|
741 |
|
742 // ok |
|
743 return ctx->chan; |
|
744 } |
|
745 |
678 |
746 |
679 /** |
747 /** |
680 * Call irc_net_add_chan while offline, and ensure that we send the JOIN request after RPL_WELCOME, and handle the join |
748 * Call irc_net_add_chan while offline, and ensure that we send the JOIN request after RPL_WELCOME, and handle the join |
681 * reply OK. |
749 * reply OK. |
682 */ |
750 */ |
704 |
772 |
705 // cleanup |
773 // cleanup |
706 irc_net_destroy(net); |
774 irc_net_destroy(net); |
707 } |
775 } |
708 |
776 |
709 /** |
|
710 * Ensure that an irc_chan_user exists for the given channel/nickname, and return it |
|
711 */ |
|
712 struct irc_chan_user* check_chan_user (struct irc_chan *chan, const char *nickname) |
|
713 { |
|
714 struct irc_chan_user *chan_user; |
|
715 |
|
716 if ((chan_user = irc_chan_get_user(chan, nickname)) == NULL) |
|
717 FATAL("user %s not found in channel %s", dump_str(nickname), dump_str(irc_chan_name(chan))); |
|
718 |
|
719 log_debug("%s -> %p: user=%p, nickname=%s", nickname, chan_user, chan_user->user, chan_user->user->nickname); |
|
720 |
|
721 assert_strcmp(chan_user->user->nickname, nickname); |
|
722 |
|
723 return chan_user; |
|
724 } |
|
725 |
|
726 void test_irc_chan_namreply (void) |
777 void test_irc_chan_namreply (void) |
|
778 { |
|
779 struct test_chan_ctx ctx; |
|
780 struct sock_test *sock = setup_sock_test(); |
|
781 struct irc_net *net = setup_irc_net(sock); |
|
782 setup_irc_chan_join(sock, net, &ctx); |
|
783 |
|
784 log_info("test irc_chan_on_RPL_NAMREPLY"); |
|
785 do_irc_chan_namreply(sock, &ctx); |
|
786 |
|
787 // cleanup |
|
788 irc_net_destroy(net); |
|
789 } |
|
790 |
|
791 void test_irc_chan_user_join (void) |
727 { |
792 { |
728 struct test_chan_ctx ctx; |
793 struct test_chan_ctx ctx; |
729 struct sock_test *sock = setup_sock_test(); |
794 struct sock_test *sock = setup_sock_test(); |
730 struct irc_net *net = setup_irc_net(sock); |
795 struct irc_net *net = setup_irc_net(sock); |
731 struct irc_chan *chan = setup_irc_chan(sock, net, &ctx); |
796 struct irc_chan *chan = setup_irc_chan(sock, net, &ctx); |
732 |
797 |
733 // RPL_NAMREPLY |
798 // have a user join |
734 log_info("test irc_chan_on_RPL_NAMREPLY"); |
799 log_info("test irc_chan_on_JOIN"); |
735 test_sock_push(sock, "353 mynick = #test :mynick userA +userB @userC\r\n"); |
800 test_sock_push(sock, ":newuser!someone@somewhere JOIN #test\r\n"); |
736 |
801 assert(ctx.on_chan_join); |
737 check_chan_user(chan, "mynick"); |
802 check_chan_user(chan, "newuser", true); |
738 check_chan_user(chan, "userA"); |
|
739 check_chan_user(chan, "userB"); |
|
740 check_chan_user(chan, "userC"); |
|
741 |
803 |
742 // cleanup |
804 // cleanup |
743 irc_net_destroy(net); |
805 irc_net_destroy(net); |
744 } |
806 } |
745 |
807 |
746 void test_irc_chan_user_join (void) |
808 void test_irc_chan_user_part (void) |
747 { |
809 { |
748 struct test_chan_ctx ctx; |
810 struct test_chan_ctx ctx; |
749 struct sock_test *sock = setup_sock_test(); |
811 struct sock_test *sock = setup_sock_test(); |
750 struct irc_net *net = setup_irc_net(sock); |
812 struct irc_net *net = setup_irc_net(sock); |
751 struct irc_chan *chan = setup_irc_chan(sock, net, &ctx); |
813 struct irc_chan *chan = setup_irc_chan(sock, net, &ctx); |
752 |
814 |
753 // RPL_NAMREPLY |
|
754 test_sock_push(sock, "353 mynick = #test :mynick userA +userB @userC\r\n"); |
|
755 |
|
756 check_chan_user(chan, "mynick"); |
|
757 check_chan_user(chan, "userA"); |
|
758 check_chan_user(chan, "userB"); |
|
759 check_chan_user(chan, "userC"); |
|
760 |
|
761 // have a user join |
815 // have a user join |
762 log_info("test irc_chan_on_JOIN"); |
816 log_info("test irc_chan_on_PART"); |
763 test_sock_push(sock, ":newuser!someone@somewhere JOIN #test\r\n"); |
817 test_sock_push(sock, ":userA!someone@somewhere PART #test\r\n"); |
764 assert(ctx.on_chan_join); |
818 assert(ctx.on_chan_part); ctx.on_chan_part = NULL; |
765 check_chan_user(chan, "newuser"); |
819 check_chan_user(chan, "userA", false); |
766 |
820 |
767 // cleanup |
821 // cleanup |
768 irc_net_destroy(net); |
822 irc_net_destroy(net); |
769 } |
823 } |
770 |
824 |
785 { "irc_conn", &test_irc_conn }, |
839 { "irc_conn", &test_irc_conn }, |
786 { "irc_net", &test_irc_net }, |
840 { "irc_net", &test_irc_net }, |
787 { "irc_chan_add_offline", &test_irc_chan_add_offline }, |
841 { "irc_chan_add_offline", &test_irc_chan_add_offline }, |
788 { "irc_chan_namreply", &test_irc_chan_namreply }, |
842 { "irc_chan_namreply", &test_irc_chan_namreply }, |
789 { "irc_chan_user_join", &test_irc_chan_user_join }, |
843 { "irc_chan_user_join", &test_irc_chan_user_join }, |
|
844 { "irc_chan_user_part", &test_irc_chan_user_part }, |
790 { NULL, NULL } |
845 { NULL, NULL } |
791 }; |
846 }; |
792 |
847 |
793 /** |
848 /** |
794 * Command-line option codes |
849 * Command-line option codes |