mocking.rst: add discussion on how to get state in funcs for mocks/fakes

This goes over using named resources and container_of(), as these are
probably the two best ways we can demonstrate for stashing away some
state.

Signed-off-by: Daniel Latypov <dlatypov@google.com>
Change-Id: I7804b75dd986a4df0cde4d8fea6b4b276029a039
diff --git a/mocking.rst b/mocking.rst
index b84bbe1..2791e87 100644
--- a/mocking.rst
+++ b/mocking.rst
@@ -241,3 +241,181 @@
 
 TODO(dlatypov@google.com): include discussion on global functions/general statefulness.
 TODO(dlatypov@google.com): include section on worked example use cases.
+
+Storing and accessing state for fakes/mocks
+===========================================
+
+One of the challenges of implementing both mocks and fakes is how to track
+state. We can't pass in additional parameters since that'll change the function
+signature, so we need some way of stashing state somewhere.
+
+Below, we have two examples of how you can do so fairly cleanly.
+
+Using named resources
+---------------------
+
+We can use ``current->kunit_test`` with ``kunit_add_named_resource`` to store
+and retrieve test-specific data, e.g.
+
+.. code-block:: c
+
+  /* in some shared file, mock_write.h/c */
+
+  /* Store some data per-test and have a kunit_resource handle for it. */
+  struct mock_write_data {
+          int times_called;
+          bool should_return_error;
+  };
+  static struct kunit_resource mock_write_data_resource;
+
+  int mock_write_init(struct kunit *test, struct mock_write_data *data) {
+          data->times_called = 0;
+          data->should_return_error = false;
+
+          return kunit_add_named_resource(test, NULL, NULL, &mock_write_data_resource,
+                                          "mock_write_data", data);
+  };
+
+  int mock_write(const char *data)
+  {
+          struct kunit_resource *resource;
+          struct mock_write_data *mock;
+
+          if (!current->kunit_test)
+                  return -1;
+
+          resource = kunit_find_named_resource(current->kunit_test, "mock_write_data");
+          if (!resource) {
+                  KUNIT_FAIL(current->kunit_test, "mock_write called before mock_write_init()!");
+                  return -1;
+          }
+
+          mock = resource->data;
+          mock->times_called++;
+          return mock->should_return_error ? -1 : 0;
+  }
+
+
+  /* Then in the test file, can use the mock like so */
+
+  static void example_write_test(struct kunit *test)
+  {
+          struct mock_write_data mock;
+          mock_write_init(test, &mock);
+
+          mock.should_return_error = true;
+          KUNIT_EXPECT_LT(test, mock_write("hi"), 0);
+
+          mock.should_return_error = false;
+          KUNIT_EXPECT_EQ(test, mock_write("hi"), 0);
+
+          KUNIT_EXPECT_EQ(test, mock.times_called, 2);
+  }
+
+Storing state without KUnit
+---------------------------
+
+The approach above is tied to KUnit, but it's obviously possible to come up
+with ways to do it without that dependency.
+
+For example, if you're targeting an ops struct, we can employ some
+``container_of()`` shenanigans.
+
+To make the example a bit simpler, let's assume our ops struct passes a pointer
+to itself for each operation.
+
+.. code-block:: c
+
+	struct writer {
+		int (*write)(struct writer *writer, const char *data);
+	};
+
+	/* in mock_writer.h/c */
+	struct mock_writer {
+		struct writer ops;
+		int times_called;
+		bool should_return_error;
+	};
+
+	static int mock_write(struct writer *writer, const char *data)
+	{
+		struct mock_writer *mock = container_of(writer, struct mock_writer, ops);
+
+		mock->times_called++;
+		return mock->should_return_error ? -1 : 0;
+	}
+
+	void init_mock_writer(struct mock_writer *mock) {
+		mock->ops.write = mock_write;
+		mock->times_called = 0;
+		mock->should_return_error = false;
+	}
+
+
+	/* Then in the test file */
+
+	static void example_simple_test(struct kunit *test)
+	{
+		struct mock_writer mock;
+		struct writer *writer = &mock.ops;
+
+		init_mock_writer(&mock);
+
+		mock.should_return_error = true;
+		KUNIT_EXPECT_LT(test, writer->write(writer, "hi"), 0);
+
+		mock.should_return_error = false;
+		KUNIT_EXPECT_EQ(test, writer->write(writer, "hi"), 0);
+
+		KUNIT_EXPECT_EQ(test, mock.times_called, 2);
+	}
+
+
+If this seems unrealistic, that's because it is, but it's not too far from the
+truth. E.g. ``struct inode`` has a ``struct inode_operations *i_ops`` member
+and each operation takes a ``struct inode*`` as an argument (or a ``struct
+dentry`` which we can easily convert over via ``d_inode()``).
+
+So in that more realistic example, we'd have:
+
+.. code-block:: c
+
+	struct mock_inode {
+		struct inode real;
+
+		/* mock/fake state stuff */
+		int readlink_err;
+		int get_acl_err;
+	};
+
+	static struct posix_acl *mock_get_acl(struct inode *inode, int type)
+	{
+		struct mock_inode *mock = container_of(inode, struct mock_inode, real);
+
+		if (mock->get_acl_err)
+			return ERR_PTR(get_acl_err);
+
+		return posix_acl_alloc(3, GFP_KERNEL);
+	}
+
+	static int mock_readlink(struct dentry *dentry, char __user * buffer, int buflen)
+	{
+		/* get mock_inode indrectly */
+		struct inode *inode = d_inode(dentry);
+		struct mock_inode *mock = container_of(inode, struct mock_inode, real);
+
+		return mock->readlink_err;
+	}
+
+	struct inode_operations mock_inode_operations = {
+		.get_acl = mock_get_acl,
+		.readlink  = mock_readlink,
+		/* ... */
+	};
+
+	void mock_inode_init(struct mock_inode *mock)
+	{
+		/* ... */
+
+		mock->real.i_ops = &mock_inode_operations;
+	}