src/test/irc_chan.c
branchnew-transport
changeset 168 a58ad50911fc
equal deleted inserted replaced
167:0d2d8ca879d8 168:a58ad50911fc
       
     1 #include "irc_chan.h"
       
     2 #include "irc_net.h"
       
     3 #include "test.h"
       
     4 
       
     5 
       
     6 static void _on_chan_self_join (struct irc_chan *chan, void *arg)
       
     7 {
       
     8     struct test_chan_ctx *ctx = arg;
       
     9 
       
    10     assert(chan == ctx->chan);
       
    11     
       
    12     ctx->on_chan_self_join = true;
       
    13 
       
    14     log_debug("on_self_join");
       
    15 }
       
    16 
       
    17 static void _on_chan_join (struct irc_chan *chan, const struct irc_nm *source, void *arg)
       
    18 {
       
    19     struct test_chan_ctx *ctx = arg;
       
    20 
       
    21     assert(chan == ctx->chan);
       
    22 
       
    23     // XXX: verify source
       
    24 
       
    25     ctx->on_chan_join = true;
       
    26 
       
    27     log_debug("on_join");
       
    28 }
       
    29 
       
    30 static void _on_chan_part (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg)
       
    31 {
       
    32     struct test_chan_ctx *ctx = arg;
       
    33 
       
    34     assert(chan == ctx->chan);
       
    35 
       
    36     // XXX: verify source
       
    37     // XXX: verify msg
       
    38 
       
    39     ctx->on_chan_part = true;
       
    40 
       
    41     log_debug("on_part");
       
    42 }
       
    43 
       
    44 
       
    45 struct irc_chan_callbacks _chan_callbacks = {
       
    46     .on_self_join       = _on_chan_self_join,
       
    47     .on_join            = _on_chan_join,
       
    48     .on_part            = _on_chan_part,
       
    49 };
       
    50 
       
    51 
       
    52 struct irc_chan_user* check_chan_user (struct irc_chan *chan, const char *nickname, bool exists)
       
    53 {
       
    54     struct irc_chan_user *chan_user = irc_chan_get_user(chan, nickname);
       
    55     
       
    56     if (exists && chan_user == NULL)
       
    57         FATAL("user %s not found in channel %s", dump_str(nickname), dump_str(irc_chan_name(chan)));
       
    58     
       
    59     if (!exists && chan_user)
       
    60         FATAL("user %s should not be on channel %s anymore", dump_str(nickname), dump_str(irc_chan_name(chan)));
       
    61 
       
    62     log_debug("%s, exists=%d -> %p: user=%p, nickname=%s", 
       
    63             nickname, exists, chan_user, chan_user ? chan_user->user : NULL, chan_user ? chan_user->user->nickname : NULL);
       
    64     
       
    65     if (chan_user)
       
    66         assert_strcmp(chan_user->user->nickname, nickname);
       
    67 
       
    68     return chan_user;
       
    69 }
       
    70 
       
    71 /**
       
    72  * Creates an irc_chan on the given irc_net, but does not check any output (useful for testing offline add).
       
    73  *
       
    74  * You must pass a test_chan_ctx for use with later operations, this will be initialized for you.
       
    75  */
       
    76 static struct irc_chan* setup_irc_chan_raw (struct irc_net *net, const char *channel, struct test_chan_ctx *ctx)
       
    77 {
       
    78     struct irc_chan *chan;
       
    79     struct irc_chan_info chan_info = {
       
    80         .channel        = channel,
       
    81     };
       
    82     struct error_info err;
       
    83     
       
    84     // initialize the given ctx
       
    85     memset(ctx, 0, sizeof(*ctx));
       
    86     ctx->channel = channel;
       
    87 
       
    88     // add a channel
       
    89     assert_success(irc_net_add_chan(net, &chan, &chan_info, &err));
       
    90     assert(!chan->joined);
       
    91     assert_success(irc_chan_add_callbacks(chan, &_chan_callbacks, ctx));
       
    92     ctx->chan = chan;
       
    93     
       
    94     // ok
       
    95     return chan;
       
    96 }
       
    97 
       
    98 /**
       
    99  * Checks that the JOIN request for a channel was sent, and sends the basic JOIN reply
       
   100  */
       
   101 static void do_irc_chan_join (struct transport_test *tp, struct test_chan_ctx *ctx)
       
   102 {
       
   103     // JOIN request
       
   104     assert(ctx->chan->joining);
       
   105     assert_transport_data(tp, "JOIN %s\r\n", ctx->channel);
       
   106 
       
   107     // JOIN reply
       
   108     transport_test_push_fmt(tp, ":mynick!user@host JOIN %s\r\n", ctx->channel);
       
   109     assert(!ctx->chan->joining && ctx->chan->joined);
       
   110     assert(ctx->on_chan_self_join);
       
   111 }
       
   112 
       
   113 /**
       
   114  * Sends a short RPL_NAMREPLY/RPL_ENDOFNAMES reply and checks that the users list matches
       
   115  */
       
   116 static void do_irc_chan_namreply (struct transport_test *tp, struct test_chan_ctx *ctx)
       
   117 {
       
   118     // RPL_NAMREPLY
       
   119     transport_test_push_fmt(tp, "353 mynick = %s :mynick userA +userB @userC\r\n", ctx->channel);
       
   120     transport_test_push_fmt(tp, "353 mynick = %s :trailingspace \r\n", ctx->channel);
       
   121     transport_test_push_fmt(tp, "366 mynick %s :End of NAMES\r\n", ctx->channel);
       
   122     
       
   123     // XXX: this should be an exclusive test, i.e. these should be the only ones...
       
   124     check_chan_user(ctx->chan, "mynick", true);
       
   125     check_chan_user(ctx->chan, "userA", true);
       
   126     check_chan_user(ctx->chan, "userB", true);
       
   127     check_chan_user(ctx->chan, "userC", true);
       
   128 }
       
   129 
       
   130 /**
       
   131  * Creates an irc_chan on the given irc_net, and checks up to the JOIN reply
       
   132  */
       
   133 static struct irc_chan* setup_irc_chan_join (struct transport_test *tp, struct irc_net *net, const char *channel, struct test_chan_ctx *ctx)
       
   134 {
       
   135     setup_irc_chan_raw(net, channel, ctx);
       
   136     do_irc_chan_join(tp, ctx);
       
   137 
       
   138     // ok
       
   139     return ctx->chan;
       
   140 }
       
   141 
       
   142 struct irc_chan* setup_irc_chan (struct transport_test *tp, struct irc_net *net, const char *channel, struct test_chan_ctx *ctx)
       
   143 {
       
   144     setup_irc_chan_raw(net, channel, ctx);
       
   145     do_irc_chan_join(tp, ctx);
       
   146     do_irc_chan_namreply(tp, ctx);
       
   147 
       
   148     // ok
       
   149     return ctx->chan;
       
   150 }
       
   151 
       
   152 
       
   153 void test_irc_chan_add_offline (void)
       
   154 {
       
   155     struct test_chan_ctx ctx;
       
   156     struct transport_test *tp = setup_transport_test();
       
   157     struct irc_net *net = setup_irc_net_unregistered(tp);
       
   158 
       
   159     // add an offline channel
       
   160     log_info("test offline irc_net_add_chan");
       
   161     struct irc_chan *chan = setup_irc_chan_raw(net, "#test", &ctx);
       
   162     assert(!chan->joining && !chan->joined);
       
   163 
       
   164     // send the registration reply
       
   165     log_info("test irc_conn_on_RPL_WELCOME");
       
   166     test_irc_net_welcome(tp, net);
       
   167     
       
   168     // test the join sequence
       
   169     log_info("test irc_chan_join/irc_chan_on_JOIN");
       
   170     do_irc_chan_join(tp, &ctx);
       
   171     
       
   172     // cleanup
       
   173     irc_net_destroy(net);
       
   174 }
       
   175 
       
   176 void test_irc_chan_namreply (void)
       
   177 {
       
   178     struct test_chan_ctx ctx;
       
   179     struct transport_test *tp = setup_transport_test();
       
   180     struct irc_net *net = setup_irc_net(tp);
       
   181     setup_irc_chan_join(tp, net, "#test", &ctx);
       
   182 
       
   183     log_info("test irc_chan_on_RPL_NAMREPLY");
       
   184     do_irc_chan_namreply(tp, &ctx);
       
   185 
       
   186     // cleanup
       
   187     irc_net_destroy(net);
       
   188 }
       
   189 
       
   190 void test_irc_chan_user_join (void)
       
   191 {
       
   192     struct test_chan_ctx ctx;
       
   193     struct transport_test *tp = setup_transport_test();
       
   194     struct irc_net *net = setup_irc_net(tp);
       
   195     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   196 
       
   197     // have a user join
       
   198     log_info("test irc_chan_on_JOIN");
       
   199     transport_test_push_fmt(tp, ":newuser!someone@somewhere JOIN %s\r\n", "#test");
       
   200     assert(ctx.on_chan_join);
       
   201     check_chan_user(chan, "newuser", true);
       
   202 
       
   203     // cleanup
       
   204     irc_net_destroy(net);
       
   205 }
       
   206 
       
   207 void test_irc_chan_user_part (void)
       
   208 {
       
   209     struct test_chan_ctx ctx;
       
   210     struct transport_test *tp = setup_transport_test();
       
   211     struct irc_net *net = setup_irc_net(tp);
       
   212     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   213 
       
   214     // have a user join
       
   215     log_info("test irc_chan_on_PART");
       
   216     transport_test_push_fmt(tp, ":userA!someone@somewhere PART %s\r\n", "#test");
       
   217     assert(ctx.on_chan_part); ctx.on_chan_part = NULL;
       
   218     check_chan_user(chan, "userA", false);
       
   219 
       
   220     // cleanup
       
   221     irc_net_destroy(net);
       
   222 }
       
   223 
       
   224 void test_irc_chan_user_kick (void)
       
   225 {
       
   226     struct test_chan_ctx ctx;
       
   227     struct transport_test *tp = setup_transport_test();
       
   228     struct irc_net *net = setup_irc_net(tp);
       
   229     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   230 
       
   231     // kick a user
       
   232     log_info("test irc_chan_on_KICK (other)");
       
   233     transport_test_push_fmt(tp, ":userA!someone@somewhere KICK %s userB\r\n", "#test");
       
   234     check_chan_user(chan, "userA", true);
       
   235     check_chan_user(chan, "userB", false);
       
   236 
       
   237     // cleanup
       
   238     irc_net_destroy(net);
       
   239 }
       
   240 
       
   241 void test_irc_chan_self_kick (void)
       
   242 {
       
   243     struct test_chan_ctx ctx;
       
   244     struct transport_test *tp = setup_transport_test();
       
   245     struct irc_net *net = setup_irc_net(tp);
       
   246     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   247 
       
   248     // kick a user
       
   249     log_info("test irc_chan_on_KICK (self)");
       
   250     transport_test_push_fmt(tp, ":userA!someone@somewhere KICK %s mynick foobar\r\n", "#test");
       
   251     assert(!chan->joined);
       
   252     assert(chan->kicked);
       
   253 
       
   254     // cleanup
       
   255     irc_net_destroy(net);
       
   256 }
       
   257 
       
   258 void test_irc_chan_user_nick (void)
       
   259 {
       
   260     struct test_chan_ctx ctx;
       
   261     struct transport_test *tp = setup_transport_test();
       
   262     struct irc_net *net = setup_irc_net(tp);
       
   263     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   264 
       
   265     // rename one of the users
       
   266     log_info("test irc_net_on_chanuser");
       
   267     transport_test_push_fmt(tp, ":userA!someone@somewhere NICK userA2\r\n");
       
   268     check_chan_user(chan, "userA", false);
       
   269     check_chan_user(chan, "userB", true);
       
   270 
       
   271     // cleanup
       
   272     irc_net_destroy(net);
       
   273 }
       
   274 
       
   275 void test_irc_chan_user_quit (void)
       
   276 {
       
   277     struct test_chan_ctx ctx;
       
   278     struct transport_test *tp = setup_transport_test();
       
   279     struct irc_net *net = setup_irc_net(tp);
       
   280     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   281 
       
   282     // rename one of the users
       
   283     log_info("test irc_net_on_chanuser");
       
   284     transport_test_push_fmt(tp, ":userA!someone@somewhere QUIT foo\r\n");
       
   285     check_chan_user(chan, "userA", false);
       
   286 
       
   287     // cleanup
       
   288     irc_net_destroy(net);
       
   289 }
       
   290 
       
   291 void _test_irc_chan_on_CTCP_ACTION (const struct irc_line *line, void *arg)
       
   292 {
       
   293     bool *flag = arg;
       
   294 
       
   295     log_debug("CTCP ACTION");
       
   296 
       
   297     *flag = true;
       
   298 }
       
   299 
       
   300 static struct irc_cmd_handler _test_irc_chan_handlers[] = {
       
   301     {   "CTCP ACTION",      &_test_irc_chan_on_CTCP_ACTION  },
       
   302     {   NULL,               NULL                            }
       
   303 };
       
   304 
       
   305 void test_irc_chan_CTCP_ACTION (void)
       
   306 {
       
   307     struct test_chan_ctx ctx;
       
   308     struct transport_test *tp = setup_transport_test();
       
   309     struct irc_net *net = setup_irc_net(tp);
       
   310     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   311     bool cb_ok = false;
       
   312 
       
   313     // add our handler
       
   314     assert_success(irc_cmd_add(&chan->handlers, _test_irc_chan_handlers, &cb_ok));
       
   315 
       
   316     // rename one of the users
       
   317     log_info("test irc_conn_on_CTCP_ACTION");
       
   318     transport_test_push_fmt(tp, ":userA!someone@somewhere PRIVMSG #test \001ACTION hello  world\001\r\n");
       
   319     assert(cb_ok);
       
   320 
       
   321     // cleanup
       
   322     irc_net_destroy(net);
       
   323 }
       
   324 
       
   325 void test_irc_chan_privmsg (void)
       
   326 {
       
   327     struct test_chan_ctx ctx;
       
   328     struct transport_test *tp = setup_transport_test();
       
   329     struct irc_net *net = setup_irc_net(tp);
       
   330     struct irc_chan *chan = setup_irc_chan(tp, net, "#test", &ctx);
       
   331 
       
   332     // rename one of the users
       
   333     log_info("test irc_chan_PRIVMSG");
       
   334     assert_success(irc_chan_PRIVMSG(chan, "foobar quux"));
       
   335     assert_transport_data(tp, "PRIVMSG #test :foobar quux\r\n");
       
   336 
       
   337     // cleanup
       
   338     irc_net_destroy(net);
       
   339 }
       
   340