CP-22686: Add unit tests for cbt-util create

From: Mark Syms <mark.syms@citrix.com>

Signed-off-by: Mark Syms <mark.syms@citrix.com>
Reviewed-by: Chandrikas Srinivasan <chandrika.srinivasan@citrix.com>

diff --git a/cbt/cbt-util.c b/cbt/cbt-util.c
index 4d52a0f..1c47b70 100644
--- a/cbt/cbt-util.c
+++ b/cbt/cbt-util.c
@@ -283,6 +283,9 @@ cbt_util_create(int argc, char **argv)
 	if (!argc || !argv)
 		goto usage;
 
+	/* Make sure we start from the start of the args */
+	optind = 1;
+
 	while ((c = getopt(argc, argv, "n:s:h")) != -1) {
 		switch (c) {
 			case 'n':
diff --git a/mockatests/cbt/Makefile.am b/mockatests/cbt/Makefile.am
index 0581b4f..b19e578 100644
--- a/mockatests/cbt/Makefile.am
+++ b/mockatests/cbt/Makefile.am
@@ -9,7 +9,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/cbt
 check_PROGRAMS = test-cbt-util
 TESTS = test-cbt-util
 
-test_cbt_util_SOURCES = test-cbt-util.c wrappers.c test-cbt-util-commands.c test-cbt-util-get.c
+test_cbt_util_SOURCES = test-cbt-util.c wrappers.c test-cbt-util-commands.c test-cbt-util-get.c test-cbt-util-create.c
 test_cbt_util_LDFLAGS = $(top_srcdir)/cbt/libcbtutil.la -lcmocka -luuid
 test_cbt_util_LDFLAGS += -Wl,--wrap=fopen,--wrap=fclose
 test_cbt_util_LDFLAGS += -Wl,--wrap=malloc,--wrap=free
diff --git a/mockatests/cbt/test-cbt-util-create.c b/mockatests/cbt/test-cbt-util-create.c
new file mode 100644
index 0000000..8450408
--- /dev/null
+++ b/mockatests/cbt/test-cbt-util-create.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017, Citrix Systems, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the names of its 
+ *     contributors may be used to endorse or promote products derived from 
+ *     this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <errno.h>
+
+#include <cbt-util-priv.h>
+#include "wrappers.h"
+#include "test-suites.h"
+
+void test_cbt_util_create_success(void **state)
+{
+	int result;
+	int file_size;
+	char* args[] = { "cbt-util", "-n", "test_disk.log", "-s", "4194304" };
+	void *log_meta;
+
+	file_size = 4194304 + sizeof(struct cbt_log_metadata);
+
+	log_meta = test_malloc(file_size);
+	FILE *test_log = fmemopen(log_meta, file_size, "w+");
+
+	will_return(__wrap_fopen, test_log);
+	expect_value(__wrap_fclose, fp, test_log);
+
+	result = cbt_util_create(5, args);
+
+	assert_int_equal(result, 0);
+	assert_int_equal(((struct cbt_log_metadata*)log_meta)->consistent, 0);
+
+	test_free(log_meta);
+}
+
+void test_cbt_util_create_file_open_failure(void **state)
+{
+	int result;
+	char* args[] = { "cbt-util", "-n", "test_disk.log", "-s", "4194304" };
+
+	will_return(__wrap_fopen, NULL);
+	/* TODO: Could do with this then making another call to mock to get the error code */
+
+	result = cbt_util_create(5, args);
+
+	assert_int_equal(result, -ENOENT);
+}
+
+void test_cbt_util_create_metadata_write_failure(void **state)
+{
+	int result;
+	char* args[] = { "cbt-util", "-n", "test_disk.log", "-s", "4194304" };
+	void *log_meta[1];
+
+	FILE *test_log = fmemopen(log_meta, 1, "w+");
+
+	/* Make IO errors happen immediately, not on flush */
+	setbuf(test_log, NULL);
+
+	will_return(__wrap_fopen, test_log);
+	expect_value(__wrap_fclose, fp, test_log);
+
+	result = cbt_util_create(5, args);
+
+	assert_int_equal(result, -EIO);
+}
+
+void test_cbt_util_create_bitmap_write_failure(void **state)
+{
+	int result;
+	char* args[] = { "cbt-util", "-n", "test_disk.log", "-s", "4194304" };
+	void *log_meta;
+
+	log_meta = test_malloc(sizeof(struct cbt_log_metadata));
+
+	FILE *test_log = fmemopen(log_meta, sizeof(struct cbt_log_metadata), "w+");
+
+	/* Make IO errors happen immediately, not on flush */
+	setbuf(test_log, NULL);
+
+	will_return(__wrap_fopen, test_log);
+	expect_value(__wrap_fclose, fp, test_log);
+
+	result = cbt_util_create(5, args);
+
+	assert_int_equal(result, -EIO);
+
+	test_free(log_meta);
+}
+
+void test_cbt_util_create_log_data_allocation_failure(void **state)
+{
+	int result;
+	char* args[] = { "cbt-util", "-n", "test_disk.log", "-s", "4194304" };
+
+	malloc_succeeds(false);
+
+	result = cbt_util_create(5, args);
+
+	assert_int_equal(result, -ENOMEM);
+
+	disable_malloc_mock();
+}
+
+void test_cbt_util_create_bitmap_allocation_failure(void **state)
+{
+	int result;
+	char* args[] = { "cbt-util", "-n", "test_disk.log", "-s", "4194304" };
+
+	malloc_succeeds(true);
+	malloc_succeeds(false);
+
+	result = cbt_util_create(5, args);
+
+	assert_int_equal(result, -ENOMEM);
+
+	disable_malloc_mock();
+}
+
+void test_cbt_util_create_no_name_failure(void **state)
+{
+	int result;
+	char* args[] = { "cbt-util", "-s", "4194304" };
+	struct printf_data *output;
+
+	output = setup_vprintf_mock(1024);
+
+	result = cbt_util_create(3, args);
+
+	assert_int_equal(result, -EINVAL);
+
+	free_printf_data(output);
+}
+
+void test_cbt_util_create_no_size_failure(void **state)
+{
+	int result;
+	char* args[] = { "cbt-util", "-n", "test_disk.log" };
+	struct printf_data *output;
+
+	output = setup_vprintf_mock(1024);
+
+	result = cbt_util_create(3, args);
+
+	assert_int_equal(result, -EINVAL);
+
+	free_printf_data(output);
+}
+
diff --git a/mockatests/cbt/test-cbt-util-get.c b/mockatests/cbt/test-cbt-util-get.c
index 8a681ad..2c69fb2 100644
--- a/mockatests/cbt/test-cbt-util-get.c
+++ b/mockatests/cbt/test-cbt-util-get.c
@@ -42,12 +42,6 @@
 #include "wrappers.h"
 #include "test-suites.h"
 
-struct cbt_log_metadata {
-	uuid_t parent;
-	uuid_t child;
-	int    consistent;
-};
-
 void test_cbt_util_get_flag(void **state)
 {
 	int result;
diff --git a/mockatests/cbt/test-cbt-util.c b/mockatests/cbt/test-cbt-util.c
index 4dc6348..0afa54d 100644
--- a/mockatests/cbt/test-cbt-util.c
+++ b/mockatests/cbt/test-cbt-util.c
@@ -40,7 +40,8 @@ int main(void)
 {
 	int result =
 		cmocka_run_group_tests_name("Command tests", cbt_command_tests, NULL, NULL) +
-		cmocka_run_group_tests_name("Get tests", cbt_get_tests, NULL, NULL);
+		cmocka_run_group_tests_name("Get tests", cbt_get_tests, NULL, NULL) +
+		cmocka_run_group_tests_name("Create tests", cbt_create_tests, NULL, NULL);
 
 	/* Need to flag that the tests are done so that the fclose mock goes quiescent */
 	disable_mocks();
diff --git a/mockatests/cbt/test-suites.h b/mockatests/cbt/test-suites.h
index 4d461b6..ab6e01c 100644
--- a/mockatests/cbt/test-suites.h
+++ b/mockatests/cbt/test-suites.h
@@ -28,16 +28,25 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef __TEST_SUITES_H__
+#define __TEST_SUITES_H__
+
 #include <setjmp.h>
 #include <cmocka.h>
+#include <uuid/uuid.h>
 
-#ifndef __TEST_SUITES_H__
-#define __TEST_SUITES_H__
+struct cbt_log_metadata {
+	uuid_t parent;
+	uuid_t child;
+	int    consistent;
+};
 
+/* Command lookup tests */
 void test_get_command_create(void **state);
 void test_get_command_set(void **state);
 void test_get_command_get(void **state);
 
+/* 'cbt-util get' tests */
 void test_cbt_util_get_flag(void **state);
 void test_cbt_util_get_parent(void **state);
 void test_cbt_util_get_child(void **state);
@@ -47,6 +56,16 @@ void test_cbt_util_get_malloc_failure(void **state);
 void test_cbt_util_get_no_name_failure(void **state);
 void test_cbt_util_get_no_command_failure(void **state);
 
+/* 'cbt-util create' tests */
+void test_cbt_util_create_success(void **state);
+void test_cbt_util_create_file_open_failure(void **state);
+void test_cbt_util_create_metadata_write_failure(void **state);
+void test_cbt_util_create_bitmap_write_failure(void **state);
+void test_cbt_util_create_log_data_allocation_failure(void **state);
+void test_cbt_util_create_bitmap_allocation_failure(void **state);
+void test_cbt_util_create_no_name_failure(void **state);
+void test_cbt_util_create_no_size_failure(void **state);
+
 /* Functions under test */
 
 extern int cbt_util_create(int , char **);
@@ -71,4 +90,15 @@ static const struct CMUnitTest cbt_get_tests[] = {
 	cmocka_unit_test(test_cbt_util_get_no_command_failure)
 };
 
+static const struct CMUnitTest cbt_create_tests[] = {
+	cmocka_unit_test(test_cbt_util_create_success),
+	cmocka_unit_test(test_cbt_util_create_file_open_failure),
+	cmocka_unit_test(test_cbt_util_create_metadata_write_failure),
+	cmocka_unit_test(test_cbt_util_create_bitmap_write_failure),
+	cmocka_unit_test(test_cbt_util_create_log_data_allocation_failure),
+	cmocka_unit_test(test_cbt_util_create_bitmap_allocation_failure),
+	cmocka_unit_test(test_cbt_util_create_no_name_failure),
+	cmocka_unit_test(test_cbt_util_create_no_size_failure)
+};
+
 #endif /* __TEST_SUITES_H__ */
