import os
from pytest import fail
from unittest.mock import MagicMock

from g2h.tree_page import TreePage

def test_init():
    repo = MagicMock()
    commit = MagicMock()
    commit.hexsha = '123'
    page = TreePage('test/tree', 'tree test', commit, 'test/sub/tree', repo, '')
    assert(page.name == 'tree test')
    assert(page.repo == repo)
    assert(page.commit == commit)
    commit.tree.join.assert_called_once_with('test/sub/tree')
    commit_no_subtree = MagicMock()
    commit_no_subtree.hexsha = '123'
    commit_no_subtree.tree = 'no sub tree'
    page_no_subtree = TreePage('test/tree', 'tree test', commit_no_subtree, '', repo, '')
    assert(page_no_subtree.name == 'tree test')
    assert(page_no_subtree.repo == repo)
    assert(page_no_subtree.commit == commit_no_subtree)
    assert(page_no_subtree.tree == 'no sub tree')

def add_nodes(parent, paths):
    nodes = []
    for node in paths:
        nodes.append(add_node(parent, node))
    return nodes

def add_node(parent, path):
    node = MagicMock()
    node.trees = []
    node.blobs = []
    node.name = path
    node.path = os.path.join(parent.path, path)
    if path.endswith('/'):
        parent.trees.append(node)
    else:
        parent.blobs.append(node)
    return node

def test_context_empty():
    commit = MagicMock()
    commit.hexsha = '123'
    page = TreePage('test/tree', 'tree test', commit, '', None, '')
    context = page.context()
    assert(context['entries'] == [])
    assert(context['title'] == 'tree test: Tree')

def test_context_filled():
    tree = MagicMock()
    tree.trees = []
    tree.blobs = []
    repo = MagicMock()
    sub_dir = add_node(tree, 'sub/')
    sub_file = add_node(sub_dir, 'file.txt')
    readme = add_node(tree, 'README')
    commit = MagicMock()
    commit.hexsha = '123'
    commit.author.email = 'unit@te.st'
    commit.tree = tree
    commit.committed_datetime = 'Date Time'
    repo.iter_commits = MagicMock(return_value=iter([commit, commit]))
    page = TreePage('test/tree', 'tree test', commit, '', repo, '')
    context = page.context()
    assert(repo.iter_commits.called)
    assert(context['title'] == 'tree test: Tree')
    assert(context['entries'] == [{'name': 'sub/', 'modified': 'Date Time'}, {'name': 'README', 'modified': 'Date Time'}])

def test_traversal():
    factory = MagicMock()
    def new_tree_sideeffect(*args, **kwargs):
        return args[1]
    factory.new_tree.side_effect = new_tree_sideeffect
    tree = MagicMock()
    tree.trees = []
    tree.blobs = []
    tree.path = ''
    root_tree = add_nodes(tree, ['README', 'sub/'])
    sub_tree = add_nodes(root_tree[1], ['main.cc', 'lib.cc', 'include/'])
    add_node(sub_tree[2], 'lib.h')
    def tree_join_sideeffect(*args, **kwargs):
        if args[0] == 'sub/':
            return root_tree[1]
        elif args[0] == 'sub/include/':
            return sub_tree[2]
        fail('Unexpected tree join: ' + args[0])
    tree.join.side_effect = tree_join_sideeffect
    commit = MagicMock()
    commit.tree = tree
    page = TreePage('test/tree', 'tree test', commit, '', None, '')
    pages = page.build_pages(factory)
    assert(len(pages) == 3)
    assert(pages[0] == '')
    assert(pages[1] == 'sub/')
    assert(pages[2] == 'sub/include/')

