summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Schlosser <christoph@linux.com>2025-08-24 17:10:11 +0200
committerChristoph Schlosser <christoph@linux.com>2025-08-24 17:10:11 +0200
commit9bd3fd1bce788dce610ad7276ce1f1634019c380 (patch)
tree59898b74445bf4a9e751b4b7bec46f85a7ad43d8
parent66dfe0e665ebeb0dce1ff290b77245e4a9fadd88 (diff)
downloadgit2hugo-9bd3fd1bce788dce610ad7276ce1f1634019c380.tar.gz
g2h: Add unit tests and restructure class layout
Instead of having a large generator class use individual pages
-rw-r--r--g2h/__init__.py0
-rw-r--r--g2h/cli.py8
-rw-r--r--g2h/gen.py49
-rw-r--r--g2h/log_page.py43
-rw-r--r--g2h/overview_page.py15
-rw-r--r--g2h/page.py18
-rw-r--r--g2h/page_factory.py13
-rw-r--r--mise.toml4
-rw-r--r--requirements.txt1
-rw-r--r--test_repo/git.tgzbin16230 -> 16230 bytes
-rw-r--r--tests/__init__.py0
-rw-r--r--tests/log_test.py189
-rw-r--r--tests/overview_test.py8
-rw-r--r--tests/page_test.py19
14 files changed, 314 insertions, 53 deletions
diff --git a/g2h/__init__.py b/g2h/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/g2h/__init__.py
diff --git a/g2h/cli.py b/g2h/cli.py
index fc14582..3beaeb2 100644
--- a/g2h/cli.py
+++ b/g2h/cli.py
@@ -2,7 +2,7 @@ import argparse
import os
from .git import Git
-from .gen import Generator
+from .page_factory import PageFactory
def parse_args():
parser = argparse.ArgumentParser(
@@ -25,9 +25,9 @@ def main():
project_name = args.name if args.name is not None else os.path.basename(args.repo_path)
tags = git.get_tags()
- gen = Generator(args.out_dir)
- gen.render_overview(project_name, branches, tags)
- gen.render_log(project_name, commits, branches, tags)
+ factory = PageFactory(args.out_dir, project_name)
+ factory.new_overview(branches, tags).render()
+ factory.new_log(commits, branches, tags).render()
if __name__ == '__main__':
main()
diff --git a/g2h/gen.py b/g2h/gen.py
deleted file mode 100644
index 9591d87..0000000
--- a/g2h/gen.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from jinja2 import Environment, FileSystemLoader
-import os
-
-def ref_names_for_commit(refs, commit_sha):
- ref_names = []
- for ref in refs:
- if ref.commit.hexsha == commit_sha:
- ref_names.append(ref.name)
-
- return ref_names
-
-class Generator:
- def __init__(self, output_dir):
- self.output_dir = output_dir
- template_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'templates'))
- self.templates = Environment(loader=FileSystemLoader(template_dir))
-
- def _render(self, template, context, out_path):
- template = self.templates.get_template(template)
- content = template.render(context)
- out_file = os.path.join(self.output_dir, out_path)
- os.makedirs(os.path.dirname(out_file), exist_ok=True)
- with open(out_file, 'w', encoding='utf-8') as f:
- f.write(content)
-
- def render_log(self, name, commits, branches, tags):
- commits_context = []
- for commit in commits:
- refs = ref_names_for_commit(branches, commit.hexsha) + ref_names_for_commit(tags, commit.hexsha)
- commit_context = {
- 'committed_datetime': commit.committed_datetime,
- 'refs': refs,
- 'summary': commit.summary
- }
- commits_context.append(commit_context)
-
- context = {
- 'commits': commits_context,
- 'title': name + ': Log'
- }
- self._render('log.md', context, 'l.md')
-
- def render_overview(self, name, branches, tags):
- context = {
- 'branches': branches,
- 'tags': tags,
- 'title': name
- }
- self._render('overview.md', context, '_index.md')
diff --git a/g2h/log_page.py b/g2h/log_page.py
new file mode 100644
index 0000000..684a758
--- /dev/null
+++ b/g2h/log_page.py
@@ -0,0 +1,43 @@
+import os
+
+from .page import Page
+
+def ref_names_for_commit(refs, commit_sha):
+ ref_names = []
+ if refs is None:
+ return ref_names
+ for ref in refs:
+ if ref.commit.hexsha == commit_sha:
+ ref_names.append(ref.name)
+
+ return ref_names
+
+class LogPage(Page):
+ def __init__(self, out_dir, name, commits, branches, tags):
+ super(LogPage, self).__init__('log.md', out_dir, 'l.md', name)
+ self.commits = commits
+ self.branches = branches
+ self.tags = tags
+
+ def _commits_with_refs(self):
+ commits_context = []
+ for commit in self.commits:
+ refs = ref_names_for_commit(self.branches, commit.hexsha) + ref_names_for_commit(self.tags, commit.hexsha)
+ commit_context = {
+ 'committed_datetime': commit.committed_datetime,
+ 'refs': refs,
+ 'summary': commit.summary
+ }
+ commits_context.append(commit_context)
+ return commits_context
+
+ def context(self):
+ commits_context = []
+ if self.commits is not None:
+ commits_context = self._commits_with_refs()
+
+ return {
+ 'commits': commits_context,
+ 'title': self.name + ': Log'
+ }
+
diff --git a/g2h/overview_page.py b/g2h/overview_page.py
new file mode 100644
index 0000000..1693b9a
--- /dev/null
+++ b/g2h/overview_page.py
@@ -0,0 +1,15 @@
+from .page import Page
+
+class OverviewPage(Page):
+ def __init__(self, out_dir, name, branches, tags):
+ super(OverviewPage, self).__init__('overview.md', out_dir, '_index.md', name)
+ self.branches = branches
+ self.tags = tags
+
+ def context(self):
+ return {
+ 'branches': self.branches,
+ 'tags': self.tags,
+ 'title': self.name
+ }
+
diff --git a/g2h/page.py b/g2h/page.py
new file mode 100644
index 0000000..44f97ee
--- /dev/null
+++ b/g2h/page.py
@@ -0,0 +1,18 @@
+from jinja2 import Environment, FileSystemLoader
+import os
+
+class Page:
+ def __init__(self, template_file, out_dir, out_file, name):
+ self.out_file_path = os.path.join(out_dir, out_file)
+ self.name = name
+ template_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'templates'))
+ self.template = Environment(loader=FileSystemLoader(template_dir)).get_template(template_file)
+
+ def context(self):
+ raise NotImplementedError("Must override context")
+
+ def render(self):
+ content = self.template.render(self.context())
+ os.makedirs(os.path.dirname(self.out_file_path), exist_ok=True)
+ with open(self.out_file_path, 'w', encoding='utf-8') as f:
+ f.write(content)
diff --git a/g2h/page_factory.py b/g2h/page_factory.py
new file mode 100644
index 0000000..dae9675
--- /dev/null
+++ b/g2h/page_factory.py
@@ -0,0 +1,13 @@
+from .overview_page import OverviewPage
+from .log_page import LogPage
+
+class PageFactory:
+ def __init__(self, out_dir, name):
+ self.out_dir = out_dir
+ self.name = name
+
+ def new_overview(self, branches, tags):
+ return OverviewPage(self.out_dir, self.name, branches, tags)
+
+ def new_log(self, commits, branches, tags):
+ return LogPage(self.out_dir, self.name, commits, branches, tags)
diff --git a/mise.toml b/mise.toml
index a6eaf5a..4756681 100644
--- a/mise.toml
+++ b/mise.toml
@@ -11,6 +11,10 @@ description = "Run g2h with the test repo"
alias = "r"
run = "rm -rf ./test_out && python3 -m g2h.cli test_repo test_out --name 'Test repo'"
+[tasks.test]
+alias = "t"
+run = "pytest"
+
[tasks.commit]
run = [
'tar czf test_repo/git.tgz -C test_repo .git',
diff --git a/requirements.txt b/requirements.txt
index a04e815..65a012c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
GitPython==3.1.45
Jinja2==3.1.6
+pytest==8.4.1
diff --git a/test_repo/git.tgz b/test_repo/git.tgz
index 8506102..16afa55 100644
--- a/test_repo/git.tgz
+++ b/test_repo/git.tgz
Binary files differ
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/__init__.py
diff --git a/tests/log_test.py b/tests/log_test.py
new file mode 100644
index 0000000..1efe3bd
--- /dev/null
+++ b/tests/log_test.py
@@ -0,0 +1,189 @@
+from g2h.log_page import LogPage
+from unittest.mock import MagicMock
+
+def test_init():
+ page = LogPage('test/log', 'log test', None, None, None)
+ assert(page.name == 'log test')
+ assert(page.out_file_path == 'test/log/l.md')
+ assert(page.template.name == 'log.md')
+
+def test_context_no_commits():
+ page = LogPage('test/log', 'log test', None, None, None)
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [])
+
+def test_context_no_branches_and_tags():
+ commit = MagicMock()
+ commit.summary = 'mock commit'
+ commit.hexsha = 1234;
+ commit.committed_datetime = 0
+ page = LogPage('test/log', 'log test', [commit], None, None)
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [{'committed_datetime': 0, 'refs': [], 'summary': 'mock commit'}])
+
+def test_context_matching_branch_no_tags():
+ commit = MagicMock()
+ commit.summary = 'mock commit'
+ commit.hexsha = 1234;
+ commit.committed_datetime = 0
+ branch = MagicMock()
+ branch.commit.hexsha = commit.hexsha
+ branch.name = 'mock branch'
+ page = LogPage('test/log', 'log test', [commit], [branch], None)
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [{'committed_datetime': 0, 'refs': ['mock branch'], 'summary': 'mock commit'}])
+
+def test_context_unmatching_branch_no_tags():
+ commit = MagicMock()
+ commit.summary = 'mock commit'
+ commit.hexsha = 1234;
+ commit.committed_datetime = 0
+ branch = MagicMock()
+ branch.commit.hexsha = 4321
+ branch.name = 'mock branch'
+ page = LogPage('test/log', 'log test', [commit], [branch], None)
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [{'committed_datetime': 0, 'refs': [], 'summary': 'mock commit'}])
+
+def test_context_no_branch_matching_tag():
+ commit = MagicMock()
+ commit.summary = 'mock commit'
+ commit.hexsha = 1234;
+ commit.committed_datetime = 0
+ tag = MagicMock()
+ tag.commit.hexsha = commit.hexsha
+ tag.name = 'mock tag'
+ page = LogPage('test/log', 'log test', [commit], None, [tag])
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [{'committed_datetime': 0, 'refs': ['mock tag'], 'summary': 'mock commit'}])
+
+def test_context_no_branch_no_matching_tag():
+ commit = MagicMock()
+ commit.summary = 'mock commit'
+ commit.hexsha = 1234;
+ commit.committed_datetime = 0
+ tag = MagicMock()
+ tag.commit.hexsha = 4321
+ tag.name = 'mock tag'
+ page = LogPage('test/log', 'log test', [commit], None, [tag])
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [{'committed_datetime': 0, 'refs': [], 'summary': 'mock commit'}])
+
+def test_context_no_matching_branch_no_matching_tag():
+ commit = MagicMock()
+ commit.summary = 'mock commit'
+ commit.hexsha = 1234;
+ commit.committed_datetime = 0
+ branch = MagicMock()
+ branch.commit.hexsha = 321
+ branch.name = 'mock branch'
+ tag = MagicMock()
+ tag.commit.hexsha = 4321
+ tag.name = 'mock tag'
+ page = LogPage('test/log', 'log test', [commit], [branch], [tag])
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [{'committed_datetime': 0, 'refs': [], 'summary': 'mock commit'}])
+
+def test_context_matching_branch_matching_tag():
+ commit = MagicMock()
+ commit.summary = 'mock commit'
+ commit.hexsha = 1234;
+ commit.committed_datetime = 0
+ branch = MagicMock()
+ branch.commit.hexsha = commit.hexsha
+ branch.name = 'mock branch'
+ tag = MagicMock()
+ tag.commit.hexsha = commit.hexsha
+ tag.name = 'mock tag'
+ page = LogPage('test/log', 'log test', [commit], [branch], [tag])
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [{'committed_datetime': 0, 'refs': ['mock branch', 'mock tag'], 'summary': 'mock commit'}])
+
+def test_multiple_commits():
+ commit1 = MagicMock()
+ commit1.summary = 'mock commit 1'
+ commit1.hexsha = 1;
+ commit1.committed_datetime = 0
+ commit2 = MagicMock()
+ commit2.summary = 'mock commit 2'
+ commit2.hexsha = 2;
+ commit2.committed_datetime = 1
+ page = LogPage('test/log', 'log test', [commit1, commit2], None, None)
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [
+ {'committed_datetime': 0, 'refs': [], 'summary': 'mock commit 1'},
+ {'committed_datetime': 1, 'refs': [], 'summary': 'mock commit 2'}
+ ])
+
+def test_multiple_commits_branch():
+ commit1 = MagicMock()
+ commit1.summary = 'mock commit 1'
+ commit1.hexsha = 1;
+ commit1.committed_datetime = 0
+ commit2 = MagicMock()
+ commit2.summary = 'mock commit 2'
+ commit2.hexsha = 2;
+ commit2.committed_datetime = 1
+ branch = MagicMock()
+ branch.commit.hexsha = 1
+ branch.name = 'mock branch'
+ page = LogPage('test/log', 'log test', [commit1, commit2], [branch], None)
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [
+ {'committed_datetime': 0, 'refs': ['mock branch'], 'summary': 'mock commit 1'},
+ {'committed_datetime': 1, 'refs': [], 'summary': 'mock commit 2'}
+ ])
+
+def test_multiple_commits_tag():
+ commit1 = MagicMock()
+ commit1.summary = 'mock commit 1'
+ commit1.hexsha = 1;
+ commit1.committed_datetime = 0
+ commit2 = MagicMock()
+ commit2.summary = 'mock commit 2'
+ commit2.hexsha = 2;
+ commit2.committed_datetime = 1
+ tag = MagicMock()
+ tag.commit.hexsha = 1
+ tag.name = 'mock tag'
+ page = LogPage('test/log', 'log test', [commit1, commit2], None, [tag])
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [
+ {'committed_datetime': 0, 'refs': ['mock tag'], 'summary': 'mock commit 1'},
+ {'committed_datetime': 1, 'refs': [], 'summary': 'mock commit 2'}
+ ])
+
+def test_multiple_commits_branch_and_tag():
+ commit1 = MagicMock()
+ commit1.summary = 'mock commit 1'
+ commit1.hexsha = 1;
+ commit1.committed_datetime = 0
+ commit2 = MagicMock()
+ commit2.summary = 'mock commit 2'
+ commit2.hexsha = 2;
+ commit2.committed_datetime = 1
+ branch = MagicMock()
+ branch.commit.hexsha = 1
+ branch.name = 'mock branch'
+ tag = MagicMock()
+ tag.commit.hexsha = 2
+ tag.name = 'mock tag'
+ page = LogPage('test/log', 'log test', [commit1, commit2], [branch], [tag])
+ context = page.context()
+ assert(context['title'] == 'log test: Log')
+ assert(context['commits'] == [
+ {'committed_datetime': 0, 'refs': ['mock branch'], 'summary': 'mock commit 1'},
+ {'committed_datetime': 1, 'refs': ['mock tag'], 'summary': 'mock commit 2'}
+ ])
+
diff --git a/tests/overview_test.py b/tests/overview_test.py
new file mode 100644
index 0000000..fa51858
--- /dev/null
+++ b/tests/overview_test.py
@@ -0,0 +1,8 @@
+from g2h.overview_page import OverviewPage
+
+def test_init():
+ page = OverviewPage('test/overview', 'overview test', 'test branch', 'test tag')
+ context = page.context()
+ assert(context['title'] == 'overview test')
+ assert(context['branches'] == 'test branch')
+ assert(context['tags'] == 'test tag')
diff --git a/tests/page_test.py b/tests/page_test.py
new file mode 100644
index 0000000..1008a8d
--- /dev/null
+++ b/tests/page_test.py
@@ -0,0 +1,19 @@
+from g2h.page import Page
+from jinja2.exceptions import TemplateNotFound
+import pytest
+
+def test_init():
+ page = Page('overview.md', 'dir', 'file', 'name')
+ assert(page.name == 'name')
+ assert(page.out_file_path == 'dir/file')
+ assert(page.template.name == 'overview.md')
+
+def test_wrong_template():
+ with pytest.raises(TemplateNotFound):
+ Page('not existant.md', 'dir', 'file', 'name')
+
+def test_no_context():
+ page = Page('overview.md', 'dir', 'file', 'name')
+ with pytest.raises(NotImplementedError):
+ page.context()
+