User tree_diff() to assert a equals b. Dump any data-structure or
    object, traverse it depth-first and apply a unified diff, to display
    the result.

    :param             a: data_structure a
    :param             b: data_structure b
    :param             n: lines of context
    :type              n: int
    :param          sort: sort the data-structure

    ATTENTION: Sorting means changing the data-structure. The test-result may
    differ. But in case of dictionaries the results become comparable because
    the sorting negates the hash-algorithms "de-sorting".

    >>> a = [
    ...     'a',
    ...     [3, 4],
    ...     {'a': [3, {'w' : set([4, 'tree', frozenset([3,5,2])])}]},
    ...     []
    ... ]
    >>> b = [
    ...     'a',
    ...     [4, 3],
    ...     {'a': [3, {'w' : set([4, '3', frozenset([2,5,3])])}]},
    ...     []
    ... ]
    >>> try:
    ...     tree_diff_assert(a, b, sort=True)
    ... except:
    ...     "GOT IT"
    'GOT IT'

    >>> a = [
    ...     'a',
    ...     [3, 4],
    ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
    ...     []
    ... ]
    >>> b = [
    ...     'a',
    ...     [4, 3],
    ...     {'a': [3, {'w' : set(['3', 4, frozenset([2,5,3])])}]},
    ...     []
    ... ]
    >>> tree_diff_assert(a, b, sort=True)

    >>> a = [
    ...     'a',
    ...     [3, 4],
    ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
    ...     []
    ... ]
    >>> b = [
    ...     'a',
    ...     [4, 3],
    ...     {'a': [3, {'w' : set(['3', 4, frozenset([2,5,3])])}]},
    ...     []
    ... ]
    >>> try:
    ...     tree_diff_assert(a, b, sort=False)
    ... except:
    ...     "GOT IT"
    'GOT IT'

def tree_diff_assert(a, b, n=5, sort=False):
    """User tree_diff() to assert a equals b. Dump any data-structure or
    object, traverse it depth-first and apply a unified diff, to display
    the result.

    :param             a: data_structure a
    :param             b: data_structure b
    :param             n: lines of context
    :type              n: int
    :param          sort: sort the data-structure

    ATTENTION: Sorting means changing the data-structure. The test-result may
    differ. But in case of dictionaries the results become comparable because
    the sorting negates the hash-algorithms "de-sorting".

    >>> a = [
    ...     'a',
    ...     [3, 4],
    ...     {'a': [3, {'w' : set([4, 'tree', frozenset([3,5,2])])}]},
    ...     []
    ... ]
    >>> b = [
    ...     'a',
    ...     [4, 3],
    ...     {'a': [3, {'w' : set([4, '3', frozenset([2,5,3])])}]},
    ...     []
    ... ]
    >>> try:
    ...     tree_diff_assert(a, b, sort=True)
    ... except:
    ...     "GOT IT"
    'GOT IT'

    >>> a = [
    ...     'a',
    ...     [3, 4],
    ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
    ...     []
    ... ]
    >>> b = [
    ...     'a',
    ...     [4, 3],
    ...     {'a': [3, {'w' : set(['3', 4, frozenset([2,5,3])])}]},
    ...     []
    ... ]
    >>> tree_diff_assert(a, b, sort=True)

    >>> a = [
    ...     'a',
    ...     [3, 4],
    ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
    ...     []
    ... ]
    >>> b = [
    ...     'a',
    ...     [4, 3],
    ...     {'a': [3, {'w' : set(['3', 4, frozenset([2,5,3])])}]},
    ...     []
    ... ]
    >>> try:
    ...     tree_diff_assert(a, b, sort=False)
    ... except:
    ...     "GOT IT"
    'GOT IT'
    """

    a = dump(a)
    b = dump(b)
    if not sort:
        a = vformat(a).split("\n")
        b = vformat(b).split("\n")
    else:
        a = vformat(recursive_sort(a)).split("\n")
        b = vformat(recursive_sort(b)).split("\n")
    msg = "\n".join(difflib.unified_diff(a, b, n=n, lineterm=""))
    if len(msg) != 0:
        assert False, "difference: \n%s" % msg