import os
import pytest

from mercurial import (
    pycompat,
)

from tortoisehg.hgqt import graph, thgrepo
from tortoisehg.util import hglib

import helpers

def setup_module():
    global _tmpdir
    _tmpdir = helpers.mktmpdir(__name__)

    setup_namedbranch()
    setup_20nodes()
    setup_20patches()
    setup_nestedbranch()
    setup_straightenedbyrevset()
    setup_bulkgraft()
    setup_commonedge()
    setup_manyheads()
    setup_obsolete()
    setup_familyline()
    setup_movedfile()

def openrepo(name):
    return thgrepo.repository(hglib.loadui(), os.path.join(_tmpdir, name))

def buildrepo(name, graphtext):
    path = os.path.join(_tmpdir, name)
    helpers.buildgraph(path, graphtext)

def buildlinetable(grapher, predicate):
    table = {}  # rev: [predicate(edge), ...
    for node in grapher:
        if not node:
            continue
        # draw overlapped lines in the same way as HgRepoListModel
        lt = {p: predicate(p, e) for p, e
                  in sorted(node.bottomlines, key=lambda pe: pe[1].importance)}
        # and sort them in (start, end) order
        lines = [l for p, l in sorted(lt.items(), key=lambda pl: pl[0])]
        table[node.rev] = lines
    return table

def buildlinecolortable(grapher):
    return buildlinetable(grapher, lambda p, e: e.color)

def buildlinecolumntable(grapher):
    linktypetags = {
        graph.LINE_TYPE_PARENT: '',
        graph.LINE_TYPE_FAMILY: 'F',
        graph.LINE_TYPE_GRAFT: 'G',
        graph.LINE_TYPE_OBSOLETE: 'O',
    }
    def predicate(p, e):
        return '%d-%d%s' % (p[0], p[1], linktypetags[e.linktype])
    return buildlinetable(grapher, predicate)

def setup_namedbranch():
    buildrepo(b'named-branch', r"""
        8
        |\  7 [files=data]
        | 6 | [merge=local]
        |/| |
        | 5 | [files=data]
        | 4 | [files=data]
        | | 3 [files=data]
        2 |/ [branch=bar files=data]
        | 1 [files=data]
        |/
        0 [files=data]
    """)

def test_linecolor_unfiltered():
    repo = openrepo(b'named-branch')
    grapher = graph.revision_grapher(repo, {})
    c0, c1, c2 = 0, 1, 2
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                              # wt
        None: [c0],           # |
                              # 8
        8: [c0, c1],          # |\
                              # | | 7
        7: [c0, c1, c2],      # | | |
                              # | 6 |
        6: [c0, c0, c1, c2],  # |/| |
                              # | 5 |
        5: [c0, c1, c2],      # | | |
                              # | 4 |
        4: [c0, c1, c2],      # | | |
                              # | | 3
        3: [c0, c1, c2],      # | |/
                              # 2 |
        2: [c0, c1],          # | |
                              # | 1
        1: [c0, c1],          # |/
                              # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_linecolor_branchfiltered():
    repo = openrepo(b'named-branch')
    grapher = graph.revision_grapher(repo, {'branch': b'default'})
    c0, c1 = 0, 1
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                      # 7
        7: [c0],      # |
                      # | 6
        6: [c0, c1],  # | |
                      # | 5
        5: [c0, c1],  # | |
                      # | 4
        4: [c0, c1],  # | |
                      # 3 |
        3: [c0, c1],  # |/
                      # 1
        1: [c0],      # |
                      # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_linecolor_filelog():
    repo = openrepo(b'named-branch')
    grapher = graph.filelog_grapher(repo, b'data')
    c0, c1, c2 = 0, 1, 2
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                          # 7
        7: [c0],          # |
                          # | 6
        6: [c0, c1, c2],  # | |\
                          # | 5 |
        5: [c0, c1, c2],  # | | |
                          # | 4 |
        4: [c0, c1, c2],  # | | |
                          # 3 | |
        3: [c0, c1, c2],  # |/ /
                          # | 2
        2: [c0, c2],      # | |
                          # 1 |
        1: [c0, c2],      # |/
                          # 0
        0: [],
        }
    assert actualtable == expectedtable

def setup_20nodes():
    # Graph.index fetches 10 nodes by default
    hg = helpers.HgClient(os.path.join(_tmpdir, b'20nodes'))
    hg.init()
    hg.ftouch(b'data')
    hg.add(b'data')
    for i in pycompat.xrange(20):
        hg.fappend(b'data', b'%d\n' % i)
        hg.commit(b'-m', b'%d' % i)

def test_graph_index():
    repo = openrepo(b'20nodes')
    grapher = graph.revision_grapher(repo, {})
    graphobj = graph.Graph(repo, grapher)
    assert len(graphobj) == 0
    assert graphobj.index(None) == 0  # working dir
    assert graphobj.index(19) == 1
    assert graphobj.index(0) == 20
    assert len(graphobj) == 21

    with pytest.raises(ValueError):
        graphobj.index(20)  # unknown

def test_graph_build_0node():
    repo = openrepo(b'20nodes')
    graphobj = graph.Graph(repo, graph.revision_grapher(repo, {}))
    graphobj.build_nodes(0)
    assert len(graphobj) == 0

def test_graph_build_1node():
    repo = openrepo(b'20nodes')
    graphobj = graph.Graph(repo, graph.revision_grapher(repo, {}))
    graphobj.build_nodes(1)
    assert len(graphobj) == 1  # [wdir]

def test_graph_build_nodes_up_to_rev():
    repo = openrepo(b'20nodes')
    graphobj = graph.Graph(repo, graph.revision_grapher(repo, {}))
    graphobj.build_nodes(rev=19)
    assert len(graphobj) == 2  # [wdir, 19]

    graphobj.build_nodes(rev=19)
    assert len(graphobj) == 2

def test_graph_build_nodes_up_to_rev_plus0():
    repo = openrepo(b'20nodes')
    graphobj = graph.Graph(repo, graph.revision_grapher(repo, {}))
    graphobj.build_nodes(0, 19)
    assert len(graphobj) == 2  # [wdir, 19]

    graphobj.build_nodes(0, 19)
    assert len(graphobj) == 2

def test_graph_build_nodes_up_to_rev_plus1():
    repo = openrepo(b'20nodes')
    graphobj = graph.Graph(repo, graph.revision_grapher(repo, {}))
    graphobj.build_nodes(1, 19)
    assert len(graphobj) == 3  # [wdir, 19, 18]

    graphobj.build_nodes(1, 18)
    assert len(graphobj) == 4  # [wdir, 19, 18, 17]

def setup_20patches():
    hg = helpers.HgClient(os.path.join(_tmpdir, b'20patches'))
    hg.init()
    hg.fappend(b'data', b'0\n')
    hg.commit(b'-Am', b'0')
    hg.fappend(b'data', b'1\n')
    hg.commit(b'-Am', b'1')
    for i in pycompat.xrange(20):
        hg.qnew(b'%d.diff' % i)
    hg.qpop(b'-a')

def test_graph_index_unapplied_patches():
    repo = openrepo(b'20patches')
    grapher = graph.revision_grapher(repo, {})
    graphobj = graph.GraphWithMq(graph.Graph(repo, grapher),
                                 repo.thgmqunappliedpatches)
    assert len(graphobj) == 20  # unapplied-patch nodes are preloaded
    assert graphobj.index(b'19.diff') == 0
    assert graphobj.index(b'0.diff') == 19
    assert graphobj.index(None) == 20  # working dir
    assert graphobj.index(1) == 21
    assert graphobj.index(0) == 22
    assert len(graphobj) == 23

def setup_nestedbranch():
    buildrepo(b'nested-branch', r"""
        9
        |\
        | 8 [files=data]
        | 7
        6 |\  [files=data]
        | | 5 [files=data]
        | 4 | [files=data]
        | | 3 [files=data]
        | |/
        2 | [files=data]
        | 1 [files=data]
        |/
        0 [files=data]
    """)

def test_linecolor_nestedbranch():
    repo = openrepo(b'nested-branch')
    grapher = graph.revision_grapher(repo, {})
    c0, c1, c2 = 0, 1, 2
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                              # wt
        None: [c0],           # |
                              # 9
        9: [c0, c1],          # |\
                              # | 8
        8: [c0, c1],          # | |
                              # | 7
        7: [c0, c1, c2],      # | |\
                              # 6 | |
        6: [c0, c1, c2],      # | | |
                              # | | 5
        5: [c0, c1, c2],      # | | |
                              # | 4 |
        4: [c0, c1, c2],      # | | |
                              # | | 3
        3: [c0, c1, c2],      # | |/
                              # 2 |
        2: [c0, c1],          # | |
                              # | 1
        1: [c0, c1],          # |/
                              # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_linecolor_filelog_nestedbranch():
    repo = openrepo(b'nested-branch')
    grapher = graph.filelog_grapher(repo, b'data')
    c0, c1, c2 = 0, 1, 2
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                              # 9
        9: [c0, c1],          # |\
                              # | 8
        8: [c0, c1],          # | |
                              # | 7
        7: [c0, c1, c2],      # | |\
                              # 6 | |
        6: [c0, c1, c2],      # | | |
                              # | | 5
        5: [c0, c1, c2],      # | | |
                              # | 4 |
        4: [c0, c1, c2],      # | | |
                              # | | 3
        3: [c0, c1, c2],      # | |/
                              # 2 |
        2: [c0, c1],          # | |
                              # | 1
        1: [c0, c1],          # |/
                              # 0
        0: [],
        }
    assert actualtable == expectedtable

def setup_straightenedbyrevset():
    buildrepo(b'straightened-by-revset', r"""
        7
        6
        |\
        5 |
        | 4
        3 |
        | 2
        |/
        1
        0
    """)

def test_linecolor_straightened_by_revset():
    repo = openrepo(b'straightened-by-revset')
    revset = {0, 1, 2, 4, 6, 7}  # exclude 3, 5
    grapher = graph.revision_grapher(repo, {"revset": revset})
    c0, c1 = 0, 1
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                              # 7
        7: [c0],              # |
                              # 6
        6: [c1],              #  \
                              #   4
        4: [c1],              #   |
                              #   2
        2: [c1],              #  /
                              # 1
        1: [c0],              # |
                              # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_linecolor_straightened_by_revset_2():
    repo = openrepo(b'straightened-by-revset')
    revset = {0, 1, 2, 3, 4, 6, 7}  # exclude 5
    grapher = graph.revision_grapher(repo, {"revset": revset})
    c0, c1 = 0, 1
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                              # 7
        7: [c0],              # |
                              # 6
        6: [c1],              # |
                              # 4
        4: [c1],              # |
                              # | 3
        3: [c1, c0],          # | |
                              # 2 |
        2: [c1, c0],          # |/
                              # 1
        1: [c0],              # |
                              # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_linecolor_straightened_by_revset_3():
    repo = openrepo(b'straightened-by-revset')
    revset = {0, 1, 2, 3, 6, 7}  # exclude 4, 5
    grapher = graph.revision_grapher(repo, {"revset": revset})
    c0, c1 = 0, 1
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                              # 7
        7: [c0],              # |
                              # 6
        6: [],                #
                              # 3
        3: [c0],              # |
                              # | 2
        2: [c0, c1],          # |/
                              # 1
        1: [c0],              # |
                              # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_linecolor_straightened_by_revset_4():
    repo = openrepo(b'straightened-by-revset')
    revset = {0, 1, 3, 4, 6, 7}  # exclude 2, 5
    grapher = graph.revision_grapher(repo, {"revset": revset})
    c0, c1 = 0, 1
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                              # 7
        7: [c0],              # |
                              # 6
        6: [c1],              #  \
                              #   4
        4: [],                #
                              # 3
        3: [c0],              # |
                              # 1
        1: [c0],              # |
                              # 0
        0: [],
        }
    assert actualtable == expectedtable

def setup_bulkgraft():
    buildrepo(b'bulkgraft', r"""
    7 [source=3]
    6 [source=2]
    5 [source=1]
    4
    | 3
    | 2 [branch=foo]
    | 1
    |/
    0
    """)

def test_linecolor_bulkgraft():
    repo = openrepo(b'bulkgraft')
    grapher = graph.revision_grapher(repo, {"showgraftsource": True})
    c0, c1, c2, c3, c4 = 0, 1, 2, 3, 4
    actualtable = buildlinecolortable(grapher)
    expectedtable = {
                                # wt
        None: [c0],             # |
                                # 7
        7: [c0, c1],            # |\
                                # 6 .
        6: [c0, c2, c1],        # |\ \
                                # 5 . .
        5: [c0, c3, c2, c1],    # |\ \ \
                                # 4 : : :
        4: [c0, c3, c2, c1],    # | : : :
                                # | : : 3
        3: [c0, c3, c2, c4],    # | : :/
                                # | : 2
        2: [c0, c3, c4],        # | :/
                                # | 1
        1: [c0, c4],            # |/
                                # 0
        0: [],
    }
    assert actualtable == expectedtable

def setup_commonedge():
    buildrepo(b'commonedge', r"""
        6
        | 5
        |/
        | 4
        |/
        | 3
        | |
        | 2
        |/
        1
        |
        0
    """)

def test_linecolor_commonedge():
    repo = openrepo(b'commonedge')
    grapher = graph.revision_grapher(repo, {})
    c0, c1, c2, c3 = 0, 1, 2, 3
    actualtable = buildlinecolortable(grapher)
    expectedtable = {       # wt
        None: [c0],         # |
                            # 6
        6: [c0],            # |
                            # | 5
        5: [c0, c1],        # |/
                            # | 4
        4: [c0, c2],        # |/
                            # | 3
        3: [c0, c3],        # | |
                            # | 2
        2: [c0, c3],        # |/
                            # 1
        1: [c0],            # |
                            # 0
        0: [],
        }
    assert actualtable == expectedtable

def setup_manyheads():
    buildrepo(b'manyheads', r"""
    8
    |\  7
    | | 6
    | |/
    | 5 [branch=foo]
    |/| 4 [branch=foo]
    3 |/
    | 2
    |/
    1
    0
    """)

def test_grapher_noopt():
    repo = openrepo(b'manyheads')
    grapher = graph.revision_grapher(repo, {})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                        # wt
        None : ['0-0'],                 # |
                                        # 8
        8 : ['0-0', '0-1'],             # |\
                                        # | | 7
        7 : ['0-0', '1-1', '2-2'],      # | | |
                                        # | | 6
        6 : ['0-0', '1-1', '2-1'],      # | |/
                                        # | 5
        5 : ['0-0', '1-0', '1-1'],      # |/|
                                        # | | 4
        4 : ['0-0', '1-1', '2-1'],      # | |/
                                        # 3 |
        3 : ['0-0', '1-1'],             # | |
                                        # | 2
        2 : ['0-0', '1-0'],             # |/
                                        # 1
        1 : ['0-0'],                    # |
                                        # 0
        0 : [],
        }
    assert actualtable == expectedtable

def test_grapher_branch_1():
    repo = openrepo(b'manyheads')
    grapher = graph.revision_grapher(repo, {'branch': b'default'})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                # wt
        None: ['0-0'],          # |
                                # 8
        8: ['0-0'],             # |
                                # 3
        3: ['0-0'],             # |
                                # | 2
        2: ['0-0', '1-0'],      # |/
                                # 1
        1: ['0-0'],             # |
                                # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_grapher_branch_2():
    repo = openrepo(b'manyheads')
    grapher = graph.revision_grapher(repo, {'branch': b'foo'})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                        # 7
        7 :['0-0'],     # |
                        # 6
        6 :['0-0'],     # |
                        # 5
        5 :[],          #
                        # 4
        4 :[],          #
        }
    assert actualtable == expectedtable

def test_grapher_branch_allparents_1():
    repo = openrepo(b'manyheads')
    grapher = graph.revision_grapher(
            repo, {'branch': b'default', 'allparents': True})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                     # wt
        None: ['0-0'],               # |
                                     # 8
        8: ['0-0', '0-1'],           # |\
                                     # | 5
        5: ['0-0', '1-0', '1-1'],    # |/|
                                     # 3 |
        3: ['0-0', '1-1'],           # | |
                                     # | 2
        2: ['0-0', '1-0'],           # |/
                                     # 1
        1: ['0-0'],                  # |
                                     # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_grapher_branch_allparents_2():
    repo = openrepo(b'manyheads')
    grapher = graph.revision_grapher(
            repo, {'branch': b'foo', 'allparents': True})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                     # 7
        7: ['0-0'],                  # |
                                     # 6
        6: ['0-0'],                  # |
                                     # 5
        5: ['0-0', '0-1'],           # |\
                                     # +---4
        4: ['0-0', '1-1', '2-0'],    # | |
                                     # | 3
        3: ['0-0', '1-1'],           # | |
                                     # 2 |
        2: ['0-0', '1-0'],           # |/
                                     # 1
        1: ['0-0'],                  # |
                                     # 0
        0: [],
        }
    assert actualtable == expectedtable

def test_grapher_revset_1():
    repo = openrepo(b'manyheads')
    revset = {8, 6, 5, 4, 3}
    grapher = graph.revision_grapher(repo, {'revset': revset})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                    # 8
        8: ['0-0', '0-1'],          # |\
                                    # | | 6
        6: ['0-0', '1-1', '2-1'],   # | |/
                                    # | 5
        5: ['0-0', '1-0'],          # |/
                                    # | 4
        4: ['0-0'],                 # |
                                    # 3
        3: [],
        }
    assert actualtable == expectedtable

def test_grapher_revset_2():
    repo = openrepo(b'manyheads')
    revset = {5, 4, 3, 2, 1}
    grapher = graph.revision_grapher(repo, {'revset': revset})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                    # 5
        5: ['0-0', '0-1'],          # |\
                                    # +---4
        4: ['0-0', '1-1', '2-0'],   # | |
                                    # | 3
        3: ['0-0', '1-1'],          # | |
                                    # 2 |
        2: ['0-0', '1-0'],          # |/
                                    # 1
        1: [],
        }
    assert actualtable == expectedtable

def test_grapher_revset_3():
    repo = openrepo(b'manyheads')
    revset = {8, 5, 3}
    grapher = graph.revision_grapher(repo, {'revset': revset})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                    # 8
        8: ['0-0', '0-1'],          # |\
                                    # | 5
        5: ['0-0', '1-0'],          # |/
                                    # 3
        3: [],                      #
        }
    assert actualtable == expectedtable

def test_grapher_showgraftsource():
    repo = openrepo(b'bulkgraft')
    grapher = graph.revision_grapher(repo, {"showgraftsource": True})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                                            # wt
        None: ['0-0'],                      # |
                                            # 7
        7: ['0-0', '0-1G'],                 # |\
                                            # 6 .
        6: ['0-0', '0-1G', '1-2G'],         # |\ \
                                            # 5 . .
        5: ['0-0', '0-1G', '1-2G', '2-3G'], # |\ \ \
                                            # 4 : : :
        4: ['0-0', '1-1G', '2-2G', '3-3G'], # | : : :
                                            # | : : 3
        3: ['0-0', '1-1G', '2-2G', '3-2'],  # | : :/
                                            # | : 2
        2: ['0-0', '1-1G', '2-1'],          # | :/
                                            # | 1
        1: ['0-0', '1-0'],                  # |/
                                            # 0
        0: [],
    }
    assert actualtable == expectedtable

def test_grapher_showgraftsource_with_branch():
    repo = openrepo(b'bulkgraft')
    grapher = graph.revision_grapher(
        repo, {"showgraftsource": True, "branch": b"default"})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                            # wt
        None: ['0-0'],      # |
                            # 7
        7: ['0-0'],         # |
                            # 6
        6: ['0-0'],         # |
                            # 5
        5: ['0-0', '0-1G'], # |\
                            # 4 :
        4: ['0-0', '1-1G'], # | :
                            # | 1
        1: ['0-0', '1-0'],  # |/
                            # 0
        0: [],
    }
    assert actualtable == expectedtable

def test_grapher_hidegraftsource():
    repo = openrepo(b'bulkgraft')
    grapher = graph.revision_grapher(repo, {})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                            # wt
        None: ['0-0'],      # |
                            # 7
        7: ['0-0'],         # |
                            # 6
        6: ['0-0'],         # |
                            # 5
        5: ['0-0'],         # |
                            # 4
        4: ['0-0'],         # |
                            # | 3
        3: ['0-0', '1-1'],  # | |
                            # | 2
        2: ['0-0', '1-1'],  # | |
                            # | 1
        1: ['0-0', '1-0'],  # |/
                            # 0
        0: [],
    }
    assert actualtable == expectedtable

def setup_obsolete():
    buildrepo(b'obsolete', r"""
    2 [precs=1]
    | 1
    |/
    0
    """)

def test_grapher_hiddenrev():
    repo = openrepo(b'obsolete')
    grapher = graph.revision_grapher(repo, {})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                            # wt
        None: ['0-0'],      # |
                            # 2
        2: ['0-0'],         # |
                            # 0
        0: [],
    }
    assert actualtable == expectedtable

def test_grapher_showobsolete():
    repo = openrepo(b'obsolete').unfiltered()
    grapher = graph.revision_grapher(repo, {'showgraftsource': True})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
                            # wt
        None: ['0-0'],      # |
                            # 2
        2: ['0-0', '0-1O'], # |`
                            # | 1
        1: ['0-0', '1-0'],  # |/
                            # 0
        0: [],
    }
    assert actualtable == expectedtable

def setup_familyline():
    buildrepo(b'familyline', r"""
    o        # 12
    |\    o  # 11
    o---+ |  # 10
    | 9 |/
    |/| 8
    | 7 |
    6 |\|
    |\| 5
    | 4 |
    |/| 3
    2 |/
    | 1 [branch=foo]
    |/
    0
    """)

def test_grapher_familyline_islands():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {12, 11}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
        12: [],
        11: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_1_parent():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {12, 10}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
        12: ['0-0'],
        10: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_2_parents():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {9, 7, 6}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {       # 9
        9: ['0-0', '0-1'],  # |\
                            # 7 |
        7: ['1-0'],         #  /
                            # 6
        6: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_1_nva():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {9, 4}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
        9: ['0-0F'],
        4: []
    }
    assert actualtable == expectedtable

def test_grapher_familyline_2_nvas():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {7, 3, 2}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 7
        7: ['0-0F', '0-1F'],  # |\
                              # | 3
        3: ['0-0F'],          # |
                              # 2    2 is treated as 1st parent because
        2: [],                #      it is ancestor of 4(1st parent of 7)
    }
    assert actualtable == expectedtable

def test_grapher_familyline_simple_case_1():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {7, 4, 3, 1}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 7
        7: ['0-0', '0-1F'],   # |\
                              # 4 |
        4: ['0-0', '1-1F'],   # | |
                              # | 3
        3: ['0-0', '1-0'],    # |/
                              # 1
        1: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_simple_case_2():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {7, 5, 4, 1}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 7
        7: ['0-0', '0-1'],    # |\
                              # | 5
        5: ['0-0', '1-1F'],   # | |
                              # 4 |
        4: ['0-0', '1-0F'],   # |/
                              # 1
        1: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_many_parents():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {12, 11, 8, 7, 6}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {                           # 12--+
        12: ['0-0F', '0-1F', '0-2F'],           # |\  |
                                                # | +---11
        11: ['0-0F', '1-1F', '2-2F', '3-1'],    # | | |
                                                # | 8 |
         8: ['0-0F', '2-1F'],                   # |  /
                                                # | 7
         7: ['0-0F'],                           # |
                                                # 6
         6: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_dont_draw_familyline_to_parent():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {6, 2}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 6
        6: ['0-0'],           # | familyline between 6 and 2 (from 6-4-2) is
                              # 2 not drawn because 2 is direct parent of 6
        2: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_dont_draw_familyline_to_ancestor_of_visible_p1():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {9, 7, 2}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 9
        9: ['0-0'],           # | familyline between 9 and 2 (from 9-6-2) is
                              # 7 not drawn because 2 is ancestor of 7
        7: ['0-0F'],          # |
                              # 2
        2: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_dont_draw_familyline_to_ancestor_of_visible_p2():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {9, 6, 1}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 9
        9: ['0-0'],           # | familyline between 9 and 2 (from 9-7-2) is
                              # 6 not drawn because 2 is ancestor of 6
        6: ['0-0F'],          # |
                              # 1
        1: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_dont_draw_familyline_to_ancestor_of_other_nva():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {9, 5, 1}})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 9
        9: ['0-0F'],          # | familyline between 9 and 1 (from 9-7-4-1) is
                              # 5 not drawn because 1 is ancestor of 5
        5: ['0-0F'],          # |
                              # 1
        1: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_branch():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {10, 9, 8, 6, 5},
                                            'branch': b'foo'})
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {         # 9
        9: ['0-0F'],          # |
                              # | 8
        8: ['0-0F', '1-0'],   # |/
                              # 5
        5: [],
    }
    assert actualtable == expectedtable

def test_grapher_familyline_invisible_earliest():
    repo = openrepo(b'familyline')
    grapher = graph.revision_grapher(repo, {'showfamilyline': True,
                                            'revset': {1, 0},
                                            'branch': b'foo'})
    # should empty queue even if the earliest revision is invisible
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
        1: [],
    }
    assert actualtable == expectedtable

def setup_movedfile():
    buildrepo(b'movedfile', r"""
    6 [files="baz"] # add baz again
    5
    4 [files="foo2=>foo3, bar=>, baz=>"]
    3 [files="foo2"]
    2 [files="foo=>foo2, bar, baz"]
    1
    0 [files="foo, bar, baz"]
    """)

def buildpathtable(grapher):
    return {n.rev: n.extra[0] for n in grapher}

def test_filelog_movedpath():
    repo = openrepo(b'movedfile')
    grapher = graph.filelog_grapher(repo, b'foo3')
    assert (buildpathtable(grapher)
            == {4: b'foo3', 3: b'foo2', 2: b'foo2', 0: b'foo'})

def test_filelog_removedpath():
    repo = openrepo(b'movedfile')
    grapher = graph.filelog_grapher(repo, b'bar')
    assert buildpathtable(grapher) == {2: b'bar', 0: b'bar'}

def test_filelog_readdedpath():
    repo = openrepo(b'movedfile')
    grapher = graph.filelog_grapher(repo, b'baz')
    assert buildpathtable(grapher) == {6: b'baz', 2: b'baz', 0: b'baz'}

def test_filelog_readded_file():
    repo = openrepo(b'movedfile')
    grapher = graph.filelog_grapher(repo, b'baz')
    actualtable = buildlinecolumntable(grapher)
    expectedtable = {
        6: [],      # 6
                    #
        2: ['0-0'], # 2
                    # |
        0: [],      # 0
    }
    assert actualtable == expectedtable
