changeset 20834:9a624c1672a3 v8.2.0969

patch 8.2.0969: assert_equal() output for dicts is hard to figure out Commit: https://github.com/vim/vim/commit/4a021dfbeee88ac09d07e257912485314ecdcabe Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jun 13 15:13:38 2020 +0200 patch 8.2.0969: assert_equal() output for dicts is hard to figure out Problem: Assert_equal() output for dicts is hard to figure out. Solution: Only show the different items.
author Bram Moolenaar <Bram@vim.org>
date Sat, 13 Jun 2020 15:15:04 +0200
parents ca13ee9c6f8a
children 097884058719
files src/testdir/test_assert.vim src/testing.c src/version.c
diffstat 3 files changed, 99 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_assert.vim
+++ b/src/testdir/test_assert.vim
@@ -50,6 +50,26 @@ func Test_assert_equal()
   call remove(v:errors, 0)
 endfunc
 
+func Test_assert_equal_dict()
+  call assert_equal(0, assert_equal(#{one: 1, two: 2}, #{two: 2, one: 1}))
+
+  call assert_equal(1, assert_equal(#{one: 1, two: 2}, #{two: 2, one: 3}))
+  call assert_match("Expected {'one': 1} but got {'one': 3} - 1 equal item omitted", v:errors[0])
+  call remove(v:errors, 0)
+
+  call assert_equal(1, assert_equal(#{one: 1, two: 2}, #{two: 22, one: 11}))
+  call assert_match("Expected {'one': 1, 'two': 2} but got {'one': 11, 'two': 22}", v:errors[0])
+  call remove(v:errors, 0)
+
+  call assert_equal(1, assert_equal(#{}, #{two: 2, one: 1}))
+  call assert_match("Expected {} but got {'one': 1, 'two': 2}", v:errors[0])
+  call remove(v:errors, 0)
+
+  call assert_equal(1, assert_equal(#{two: 2, one: 1}, #{}))
+  call assert_match("Expected {'one': 1, 'two': 2} but got {}", v:errors[0])
+  call remove(v:errors, 0)
+endfunc
+
 func Test_assert_equalfile()
   call assert_equal(1, assert_equalfile('abcabc', 'xyzxyz'))
   call assert_match("E485: Can't read file abcabc", v:errors[0])
--- a/src/testing.c
+++ b/src/testing.c
@@ -131,12 +131,16 @@ fill_assert_error(
     garray_T	*gap,
     typval_T	*opt_msg_tv,
     char_u      *exp_str,
-    typval_T	*exp_tv,
-    typval_T	*got_tv,
+    typval_T	*exp_tv_arg,
+    typval_T	*got_tv_arg,
     assert_type_T atype)
 {
     char_u	numbuf[NUMBUFLEN];
     char_u	*tofree;
+    typval_T	*exp_tv = exp_tv_arg;
+    typval_T	*got_tv = got_tv_arg;
+    int		did_copy = FALSE;
+    int		omitted = 0;
 
     if (opt_msg_tv->v_type != VAR_UNKNOWN)
     {
@@ -153,6 +157,62 @@ fill_assert_error(
 	ga_concat(gap, (char_u *)"Expected ");
     if (exp_str == NULL)
     {
+	// When comparing dictionaries, drop the items that are equal, so that
+	// it's a lot easier to see what differs.
+	if (atype != ASSERT_NOTEQUAL
+		&& exp_tv->v_type == VAR_DICT && got_tv->v_type == VAR_DICT
+		&& exp_tv->vval.v_dict != NULL && got_tv->vval.v_dict != NULL)
+	{
+	    dict_T	*exp_d = exp_tv->vval.v_dict;
+	    dict_T	*got_d = got_tv->vval.v_dict;
+	    hashitem_T	*hi;
+	    dictitem_T	*item2;
+	    int		todo;
+
+	    did_copy = TRUE;
+	    exp_tv->vval.v_dict = dict_alloc();
+	    got_tv->vval.v_dict = dict_alloc();
+	    if (exp_tv->vval.v_dict == NULL || got_tv->vval.v_dict == NULL)
+		return;
+
+	    todo = (int)exp_d->dv_hashtab.ht_used;
+	    for (hi = exp_d->dv_hashtab.ht_array; todo > 0; ++hi)
+	    {
+		if (!HASHITEM_EMPTY(hi))
+		{
+		    item2 = dict_find(got_d, hi->hi_key, -1);
+		    if (item2 == NULL || !tv_equal(&HI2DI(hi)->di_tv,
+						  &item2->di_tv, FALSE, FALSE))
+		    {
+			// item of exp_d not present in got_d or values differ.
+			dict_add_tv(exp_tv->vval.v_dict,
+					(char *)hi->hi_key, &HI2DI(hi)->di_tv);
+			if (item2 != NULL)
+			    dict_add_tv(got_tv->vval.v_dict,
+					    (char *)hi->hi_key, &item2->di_tv);
+		    }
+		    else
+			++omitted;
+		    --todo;
+		}
+	    }
+
+	    // Add items only present in got_d.
+	    todo = (int)got_d->dv_hashtab.ht_used;
+	    for (hi = got_d->dv_hashtab.ht_array; todo > 0; ++hi)
+	    {
+		if (!HASHITEM_EMPTY(hi))
+		{
+		    item2 = dict_find(exp_d, hi->hi_key, -1);
+		    if (item2 == NULL)
+			// item of got_d not present in exp_d
+			dict_add_tv(got_tv->vval.v_dict,
+					(char *)hi->hi_key, &HI2DI(hi)->di_tv);
+		    --todo;
+		}
+	    }
+	}
+
 	ga_concat_shorten_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0));
 	vim_free(tofree);
     }
@@ -168,6 +228,21 @@ fill_assert_error(
 	    ga_concat(gap, (char_u *)" but got ");
 	ga_concat_shorten_esc(gap, tv2string(got_tv, &tofree, numbuf, 0));
 	vim_free(tofree);
+
+	if (omitted != 0)
+	{
+	    char buf[100];
+
+	    vim_snprintf(buf, 100, " - %d equal item%s omitted",
+					     omitted, omitted == 1 ? "" : "s");
+	    ga_concat(gap, (char_u *)buf);
+	}
+    }
+
+    if (did_copy)
+    {
+	clear_tv(exp_tv);
+	clear_tv(got_tv);
     }
 }
 
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    969,
+/**/
     968,
 /**/
     967,