kunit: mock : Add three Cardinality expectation macro helpers.

- AtLeast : An expectation is called at least n times.
- AtMost : An expectation is called at most n times.
- Between : An expectation is called beween n to m(inclusive) times.

Change-Id: Ic1d96efce855495c8484512161a58df95cd93658
Signed-off-by: Harshal Tushar Lehri <halehri@google.com>
diff --git a/include/test/mock.h b/include/test/mock.h
index fd0dc4c..e599d21 100644
--- a/include/test/mock.h
+++ b/include/test/mock.h
@@ -292,6 +292,62 @@
 }
 
 /**
+ * AtLeast() - sets the minimum number of times a method is expected to be
+ *	called with matching parameters
+ * @times: the minimum number of times expected
+ * @expectation: the expectation to set
+ *
+ * Return:
+ * the same &struct mock_expectation passed in
+ */
+static inline struct mock_expectation *AtLeast(
+        int times,
+	struct mock_expectation *expectation)
+{
+	expectation->min_calls_expected = times;
+	expectation->max_calls_expected = INT_MAX;
+	return expectation;
+}
+
+/**
+ * AtMost() - sets the maximum number of times a method is expected to be
+ *	called with matching parameters
+ * @times: the maximum number of times expected
+ * @expectation: the expectation to set
+ *
+ * Return:
+ * the same &struct mock_expectation passed in
+ */
+static inline struct mock_expectation *AtMost(
+        int times,
+	struct mock_expectation *expectation)
+{
+	expectation->min_calls_expected = 0;
+	expectation->max_calls_expected = times;
+	return expectation;
+}
+
+/**
+ * Between() - sets the minimum and maximum number of times a method is
+ *	expected to be called with matching parameters
+ * @min_times: the minimum number of times expected
+ * @max_times: the maximum number of times expected
+ * @expectation: the expectation to set
+ *
+ * Return:
+ * the same &struct mock_expectation passed in
+ */
+static inline struct mock_expectation *Between(
+        int min_times,
+        int max_times,
+	struct mock_expectation *expectation)
+{
+	expectation->min_calls_expected = min_times;
+	expectation->max_calls_expected = max_times;
+	return expectation;
+}
+
+/**
  * Never() - alias for Times(0)
  * @expectation: the expectation to set
  *
diff --git a/test/mock-test.c b/test/mock-test.c
index 7a6ce3b..48ac0ac 100644
--- a/test/mock-test.c
+++ b/test/mock-test.c
@@ -610,6 +610,154 @@
         mock_validate_expectations(mock);
 }
 
+static void mock_test_atleast(struct test *test)
+{
+	struct mock_test_context *ctx = test->priv;
+	struct MOCK(test) *mock_test = ctx->mock_test;
+	struct test *trgt = mock_get_trgt(mock_test);
+	struct mock *mock = ctx->mock;
+
+	struct mock_param_matcher *a_matchers[] = { int_eq(trgt, 1) };
+	struct mock_param_matcher *b_matchers[] = { int_eq(trgt, 2) };
+
+        struct mock_expectation *a = mock_add_matcher(mock, "a", mock_stub,
+                a_matchers, param_len);
+	struct mock_expectation *b = mock_add_matcher(mock, "b", mock_stub,
+                b_matchers, param_len);
+
+        AtLeast(2, a);
+        AtLeast(1, b);
+	Never(EXPECT_CALL(fail(mock_get_ctrl(mock_test), any(test))));
+
+        mock->do_expect(mock, "a", mock_stub, param_type, a_params, param_len);
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+        mock->do_expect(mock, "a", mock_stub, param_type, a_params, param_len);
+        mock->do_expect(mock, "a", mock_stub, param_type, a_params, param_len);
+
+        mock_validate_expectations(mock);
+}
+
+static void mock_test_atleast_fail(struct test *test)
+{
+	struct mock_test_context *ctx = test->priv;
+	struct MOCK(test) *mock_test = ctx->mock_test;
+	struct test *trgt = mock_get_trgt(mock_test);
+	struct mock *mock = ctx->mock;
+
+	struct mock_param_matcher *b_matchers[] = { int_eq(trgt, 2) };
+
+        struct mock_expectation *b = mock_add_matcher(mock, "b", mock_stub,
+                b_matchers, param_len);
+
+        AtLeast(2, b);
+        EXPECT_CALL(fail(mock_get_ctrl(mock_test), any(test)));
+
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+
+        mock_validate_expectations(mock);
+}
+
+static void mock_test_atmost(struct test *test)
+{
+	struct mock_test_context *ctx = test->priv;
+	struct MOCK(test) *mock_test = ctx->mock_test;
+	struct test *trgt = mock_get_trgt(mock_test);
+	struct mock *mock = ctx->mock;
+
+	struct mock_param_matcher *a_matchers[] = { int_eq(trgt, 1) };
+	struct mock_param_matcher *b_matchers[] = { int_eq(trgt, 2) };
+	struct mock_param_matcher *c_matchers[] = { int_eq(trgt, 3) };
+
+        struct mock_expectation *a = mock_add_matcher(mock, "a", mock_stub,
+                a_matchers, param_len);
+        struct mock_expectation *b = mock_add_matcher(mock, "b", mock_stub,
+                b_matchers, param_len);
+	struct mock_expectation *c = mock_add_matcher(mock, "c", mock_stub,
+                c_matchers, param_len);
+
+        AtMost(2, a);
+        AtMost(1, b);
+        AtMost(2, c);
+	Never(EXPECT_CALL(fail(mock_get_ctrl(mock_test), any(test))));
+
+        mock->do_expect(mock, "a", mock_stub, param_type, a_params, param_len);
+        mock->do_expect(mock, "a", mock_stub, param_type, a_params, param_len);
+	mock->do_expect(mock, "c", mock_stub, param_type, c_params, param_len);
+
+        mock_validate_expectations(mock);
+}
+
+static void mock_test_atmost_fail(struct test *test)
+{
+	struct mock_test_context *ctx = test->priv;
+	struct MOCK(test) *mock_test = ctx->mock_test;
+	struct test *trgt = mock_get_trgt(mock_test);
+	struct mock *mock = ctx->mock;
+
+	struct mock_param_matcher *b_matchers[] = { int_eq(trgt, 2) };
+
+        struct mock_expectation *b = mock_add_matcher(mock, "b", mock_stub,
+                b_matchers, param_len);
+
+        AtMost(2, b);
+        EXPECT_CALL(fail(mock_get_ctrl(mock_test), any(test)));
+
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+        mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+
+        mock_validate_expectations(mock);
+}
+
+static void mock_test_between(struct test *test)
+{
+	struct mock_test_context *ctx = test->priv;
+	struct MOCK(test) *mock_test = ctx->mock_test;
+	struct test *trgt = mock_get_trgt(mock_test);
+	struct mock *mock = ctx->mock;
+
+	struct mock_param_matcher *b_matchers[] = { int_eq(trgt, 2) };
+
+        struct mock_expectation *b = mock_add_matcher(mock, "b", mock_stub,
+                b_matchers, param_len);
+
+        Between(2, 4, b);
+        Never(EXPECT_CALL(fail(mock_get_ctrl(mock_test), any(test))));
+
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+        mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+
+        mock_validate_expectations(mock);
+}
+
+static void mock_test_between_fail(struct test *test)
+{
+	struct mock_test_context *ctx = test->priv;
+	struct MOCK(test) *mock_test = ctx->mock_test;
+	struct test *trgt = mock_get_trgt(mock_test);
+	struct mock *mock = ctx->mock;
+
+	struct mock_param_matcher *a_matchers[] = { int_eq(trgt, 1) };
+	struct mock_param_matcher *b_matchers[] = { int_eq(trgt, 2) };
+
+        struct mock_expectation *a = mock_add_matcher(mock, "a", mock_stub,
+                a_matchers, param_len);
+        struct mock_expectation *b = mock_add_matcher(mock, "b", mock_stub,
+                b_matchers, param_len);
+
+        Between(2, 3, a);
+        Between(1, 2, b);
+        Times(2, EXPECT_CALL(fail(mock_get_ctrl(mock_test), any(test))));
+
+	mock->do_expect(mock, "a", mock_stub, param_type, a_params, param_len);
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+        mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+	mock->do_expect(mock, "b", mock_stub, param_type, b_params, param_len);
+
+        mock_validate_expectations(mock);
+}
+
 void *do_mocked_fail(struct mock_action *this, const void **params, int len)
 {
 	static const int ret;
@@ -672,7 +820,13 @@
 	TEST_CASE(mock_test_in_sequence_bac_success),
 	TEST_CASE(mock_test_in_sequence_no_a_fail),
         TEST_CASE(mock_test_in_sequence_retire_on_saturation),
-	{},
+        TEST_CASE(mock_test_atleast),
+        TEST_CASE(mock_test_atleast_fail),
+        TEST_CASE(mock_test_atmost),
+        TEST_CASE(mock_test_atmost_fail),
+        TEST_CASE(mock_test_between),
+        TEST_CASE(mock_test_between_fail),
+        {},
 };
 
 static struct test_module mock_test_module = {