1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141

ipc / ipc_test_sink.h [blame]

// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IPC_IPC_TEST_SINK_H_
#define IPC_IPC_TEST_SINK_H_

#include <stddef.h>
#include <stdint.h>

#include <utility>
#include <vector>

#include "base/observer_list.h"
#include "build/build_config.h"
#include "ipc/ipc_channel.h"

namespace IPC {

class Message;

// This test sink provides a "sink" for IPC messages that are sent. It allows
// the caller to query messages received in various different ways.  It is
// designed for tests for objects that use the IPC system.
//
// Typical usage:
//
//   test_sink.ClearMessages();
//   do_something();
//
//   // We should have gotten exactly one update state message.
//   EXPECT_TRUE(test_sink.GetUniqeMessageMatching(ViewHostMsg_Update::ID));
//   // ...and no start load messages.
//   EXPECT_FALSE(test_sink.GetFirstMessageMatching(ViewHostMsg_Start::ID));
//
//   // Now inspect a message. This assumes a message that was declared like
//   // this: IPC_MESSAGE_ROUTED2(ViewMsg_Foo, bool, int)
//   IPC::Message* msg = test_sink.GetFirstMessageMatching(ViewMsg_Foo::ID));
//   ASSERT_TRUE(msg);
//   bool first_param;
//   int second_param;
//   ViewMsg_Foo::Read(msg, &first_param, &second_param);
//
//   // Go on to the next phase of the test.
//   test_sink.ClearMessages();
//
// To read a sync reply, do this:
//
//   IPC::Message* msg = test_sink.GetUniqueMessageMatching(IPC_REPLY_ID);
//   ASSERT_TRUE(msg);
//   base::TupleTypes<ViewHostMsg_Foo::ReplyParam>::ValueTuple reply_data;
//   EXPECT_TRUE(ViewHostMsg_Foo::ReadReplyParam(msg, &reply_data));
//
// You can also register to be notified when messages are posted to the sink.
// This can be useful if you need to wait for a particular message that will
// be posted asynchronously.  Example usage:
//
//   class MyListener : public IPC::Listener {
//    public:
//     MyListener(const base::RepeatingClosure& closure)
//       : message_received_closure_(closure) {}
//     virtual bool OnMessageReceived(const IPC::Message& msg) {
//       <do something with the message>
//       message_received_closure_.Run();
//       return false;  // to store the message in the sink, or true to drop it
//     }
//    private:
//     base::RepeatingClosure message_received_closure_;
//   };
//
//   base::RunLoop run_loop;
//   MyListener listener(run_loop.QuitClosure());
//   test_sink.AddFilter(&listener);
//   StartSomeAsynchronousProcess(&test_sink);
//   run_loop.Run();
//   <inspect the results>
//   ...
//
// To hook up the sink, all you need to do is call OnMessageReceived when a
// message is received.
class TestSink : public Channel {
 public:
  TestSink();

  TestSink(const TestSink&) = delete;
  TestSink& operator=(const TestSink&) = delete;

  ~TestSink() override;

  // Interface in IPC::Channel. This copies the message to the sink and then
  // deletes it.
  bool Send(IPC::Message* message) override;
  [[nodiscard]] bool Connect() override;
  void Close() override;

  // Used by the source of the messages to send the message to the sink. This
  // will make a copy of the message and store it in the list.
  bool OnMessageReceived(const Message& msg);

  // Returns the number of messages in the queue.
  size_t message_count() const { return messages_.size(); }

  // Clears the message queue of saved messages.
  void ClearMessages();

  // Returns the message at the given index in the queue. The index may be out
  // of range, in which case the return value is NULL. The returned pointer will
  // only be valid until another message is received or the list is cleared.
  const Message* GetMessageAt(size_t index) const;

  // Returns the first message with the given ID in the queue. If there is no
  // message with the given ID, returns NULL. The returned pointer will only be
  // valid until another message is received or the list is cleared.
  const Message* GetFirstMessageMatching(uint32_t id) const;

  // Returns the message with the given ID in the queue. If there is no such
  // message or there is more than one of that message, this will return NULL
  // (with the expectation that you'll do an ASSERT_TRUE() on the result).
  // The returned pointer will only be valid until another message is received
  // or the list is cleared.
  const Message* GetUniqueMessageMatching(uint32_t id) const;

  // Adds the given listener as a filter to the TestSink.
  // When a message is received by the TestSink, it will be dispatched to
  // the filters, in the order they were added.  If a filter returns true
  // from OnMessageReceived, subsequent filters will not receive the message
  // and the TestSink will not store it.
  void AddFilter(Listener* filter);

  // Removes the given filter from the TestSink.
  void RemoveFilter(Listener* filter);

 private:
  // The actual list of received messages.
  std::vector<Message> messages_;
  base::ObserverList<Listener>::Unchecked filter_list_;
};

}  // namespace IPC

#endif  // IPC_IPC_TEST_SINK_H_