diff --git a/Makefile b/Makefile
index 4016da6e39..eabbfe32cf 100644
--- a/Makefile
+++ b/Makefile
@@ -1335,6 +1335,7 @@ THIRD_PARTY_SOURCES += sha1dc/%
 
 UNIT_TEST_PROGRAMS += t-basic
 UNIT_TEST_PROGRAMS += t-strbuf
+UNIT_TEST_PROGRAMS += t-progress
 UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_DIR)/%$X,$(UNIT_TEST_PROGRAMS))
 UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
 UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
diff --git a/t/unit-tests/.gitignore b/t/unit-tests/.gitignore
index e292d58348..cf5eb4803e 100644
--- a/t/unit-tests/.gitignore
+++ b/t/unit-tests/.gitignore
@@ -1,2 +1,3 @@
 /t-basic
 /t-strbuf
+/t-progress
diff --git a/t/unit-tests/t-progress.c b/t/unit-tests/t-progress.c
new file mode 100644
index 0000000000..437d6acf16
--- /dev/null
+++ b/t/unit-tests/t-progress.c
@@ -0,0 +1,229 @@
+#include "test-lib.h"
+#include "progress.c"
+
+
+static void t_simple_progress()
+{
+	int total = 4;
+	struct progress *progress = NULL;
+	int i;
+	progress = start_progress("Working hard", total);
+	for (i = 1; i <= total; i++) {
+		display_progress(progress, i);
+		check_uint(i, ==, progress->last_value);
+		check_str(progress->title, "Working hard");
+		check_int(progress->last_percent, ==, i * 100 / total);
+	}
+	return;
+}
+
+static void t_simple_progress_percent_text()
+{
+	int total = 4;
+	struct progress *progress = NULL;
+	int i;
+	char *expected[] = {
+		"  0% (0/4)",
+		" 25% (1/4)",
+		" 50% (2/4)",
+		" 75% (3/4)",
+		"100% (4/4)"
+		};
+	char *instructions[] = {
+		"progress",
+		"progress",
+		"progress",
+		"progress",
+		"progress"
+	};
+	int value[] = {
+		0,
+		1,
+		2,
+		3,
+		4
+	};
+	progress = start_progress("Working hard", total);
+	for (i = 0; i < 5; i++) {
+		if(strcmp(instructions[i], "progress")==0){
+			display_progress(progress, value[i]);
+			check_str(progress->title, "Working hard");
+			check_str(progress->counters_sb.buf, expected[i]);
+			check_uint(i * (100 / total), ==, progress->last_percent);
+		}
+	}
+	return;
+}
+
+static void t_progress_display_breaks_long_lines_1()
+{
+	int total = 100000;
+	struct progress *progress = NULL;
+	int i;
+	char *expected[4] = {
+		"  0% (100/100000)",
+		"  1% (1000/100000)",
+		" 10% (10000/100000)",
+		"100% (100000/100000)"
+	};
+	char *instructions[] = {
+		"progress",
+		"progress",
+		"progress",
+		"progress"
+	};
+	int value[] = {
+		100,
+		1000,
+		10000,
+		100000
+	};
+	progress = start_progress(
+		"Working hard.......2.........3.........4.........5.........6",
+		total);
+	for (i = 0; i < 4; i++) {
+		if(strcmp(instructions[i], "progress")==0){
+			display_progress(progress, value[i]);
+		}
+		check_str(progress->title, "Working hard.......2.........3.........4.........5.........6");
+		check_str(progress->counters_sb.buf, expected[i]);
+	}
+	return;
+}
+
+static void t_progress_display_breaks_long_lines_2()
+{
+	int total = 100000;
+	struct progress *progress = NULL;
+	int i;
+	char *expected[] = {
+		"",
+		"  0% (1/100000)",
+		"",
+		"  0% (2/100000)",
+		" 10% (10000/100000)",
+		"100% (100000/100000)"
+	};
+	char *instructions[] = {
+		"update",
+		"progress",
+		"update",
+		"progress",
+		"progress",
+		"progress"
+	};
+	int value[] = {
+		-1,
+		1,
+		-1,
+		2,
+		10000,
+		100000
+	};
+	progress = start_progress(
+		"Working hard.......2.........3.........4.........5.........6",
+		total);
+	for (i = 0; i < 5; i++) {
+		if(strcmp(instructions[i], "progress")==0){
+			display_progress(progress, value[i]);
+			check_str(progress->title, "Working hard.......2.........3.........4.........5.........6");
+			check_str(progress->counters_sb.buf, expected[i]);
+		}else if(strcmp(instructions[i], "update")==0){
+			progress_test_force_update();
+		}
+	}
+	return;
+}
+
+static void t_progress_display_breaks_long_lines_3()
+{
+	int total = 100000;
+	struct progress *progress = NULL;
+	int i;
+	char *expected[4] = {
+		" 25% (25000/100000)",
+		" 50% (50000/100000)",
+		" 75% (75000/100000)",
+		"100% (100000/100000)"
+	};
+	char *instructions[] = {
+		"progress",
+		"progress",
+		"progress",
+		"progress"
+	};
+	int value[] = {
+		25000,
+		50000,
+		75000,
+		100000
+	};
+	progress = start_progress(
+		"Working hard.......2.........3.........4.........5.........6",
+		total);
+	for (i = 0; i < 4; i++) {
+		if(strcmp(instructions[i], "progress")==0){
+			display_progress(progress, value[i]);
+			check_str(progress->title, "Working hard.......2.........3.........4.........5.........6");
+			check_str(progress->counters_sb.buf, expected[i]);
+		}else if(strcmp(instructions[i], "update")==0){
+			progress_test_force_update();
+		}
+	}
+	return;
+}
+
+
+static void t_progress_shortens_crazy_caller()
+{
+	int total = 1000;
+	struct progress *progress = NULL;
+	int i;
+	char *expected[4] = {
+		" 10% (100/1000)",
+		" 20% (200/1000)",
+		"  0% (1/1000)",
+		"100% (1000/1000)"
+	};
+	char *instructions[] = {
+		"progress",
+		"progress",
+		"progress",
+		"progress"
+	};
+	int value[] = {
+		100,
+		200,
+		1,
+		1000
+	};
+	progress = start_progress(
+		"Working hard.......2.........3.........4.........5.........6",
+		total);
+	for (i = 0; i < 4; i++) {
+		if(strcmp(instructions[i], "progress")==0){
+			display_progress(progress, value[i]);
+			check_str(progress->title, "Working hard.......2.........3.........4.........5.........6");
+			check_str(progress->counters_sb.buf, expected[i]);
+		}else if(strcmp(instructions[i], "update")==0){
+			progress_test_force_update();
+		}
+	}
+	return;
+}
+
+int cmd_main(int argc, const char **argv)
+{
+	TEST(t_simple_progress(), "Simple progress upto 3 units");
+	TEST(t_simple_progress_percent_text(),
+	     "Simple progress with percent output");
+	TEST(t_progress_display_breaks_long_lines_1(),
+	     "progress display breaks long lines #1");
+	TEST(t_progress_display_breaks_long_lines_2(),
+	     "progress display breaks long lines #2");
+	TEST(t_progress_display_breaks_long_lines_3(),
+	     "progress display breaks long lines #3");
+	TEST(t_progress_shortens_crazy_caller(),
+	     "progress shortens - crazy caller");
+	return test_done();
+}
