diff src/testing.c @ 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 b9a6a129b94e
children 2616c5a337e0
line wrap: on
line diff
--- 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);
     }
 }