From 985ae47b18ab67b23ca63486bc5a7547948b6f55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johnny=20Miller=20=28=E9=94=BA=E4=BF=8A=29?=
 <johnnysviva@outlook.com>
Date: Sun, 14 May 2023 15:14:31 +0800
Subject: [PATCH] perf($Benchmark): add more functions performance benchmark

---
 python_boilerplate/common/common_function.py | 13 +++++++++
 tests/common/test_common_function.py         | 28 +++++++++++++++++++-
 tests/demo/test_arrow_usage.py               |  5 ++++
 tests/demo/test_pydantic_usage.py            | 17 ++++++++++++
 tests/template/test_html_template.py         |  5 ++++
 5 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/python_boilerplate/common/common_function.py b/python_boilerplate/common/common_function.py
index 1f715bc..d7bfaa9 100644
--- a/python_boilerplate/common/common_function.py
+++ b/python_boilerplate/common/common_function.py
@@ -1,6 +1,7 @@
 import getpass
 import os
 from datetime import date, datetime
+from math import ceil
 from pathlib import Path
 from typing import Any, Final
 
@@ -86,3 +87,15 @@ def json_serial(obj: Any) -> str | dict[str, Any]:
     if isinstance(obj, set):
         return str(obj)
     return obj.__dict__
+
+
+def chunk_into_n(a_list: list[Any], n: int) -> list[list[Any]]:
+    """
+    Chunk a list into smaller chunks.
+
+    :param a_list: a list
+    :param n: the number of chunks going to be split
+    :return: chunks list
+    """
+    size = ceil(len(a_list) / n)
+    return [a_list[x * size : x * size + size] for x in list(range(n))]
diff --git a/tests/common/test_common_function.py b/tests/common/test_common_function.py
index 10888e4..03e0e7d 100644
--- a/tests/common/test_common_function.py
+++ b/tests/common/test_common_function.py
@@ -1,7 +1,12 @@
 from loguru import logger
+from pytest_benchmark.fixture import BenchmarkFixture
 from pytest_mock import MockerFixture
 
-from python_boilerplate.common.common_function import get_cpu_count, get_login_user
+from python_boilerplate.common.common_function import (
+    chunk_into_n,
+    get_cpu_count,
+    get_login_user,
+)
 
 
 def test_get_cpu_count_when_cpu_count_is_none_then_returns_4(
@@ -36,3 +41,24 @@ def test_get_login_user_when_exception_raised_then_returns_default_user(
     user = get_login_user()
     assert user == "default_user"
     patch.assert_called_once()
+
+
+def test_chunk_into_n() -> None:
+    chunks = chunk_into_n([1, 2, 3, 4, 5, 6, 7, 8, 9], 3)
+    assert len(chunks) == 3
+    assert len(chunks[0]) == 3
+    assert len(chunks[1]) == 3
+    assert len(chunks[2]) == 3
+    logger.info(f"Chunks: {chunks}")
+
+
+def test_get_cpu_count_benchmark(benchmark: BenchmarkFixture) -> None:
+    benchmark(get_cpu_count)
+
+
+def test_get_login_user_benchmark(benchmark: BenchmarkFixture) -> None:
+    benchmark(get_login_user)
+
+
+def test_chunk_into_n_benchmark(benchmark: BenchmarkFixture) -> None:
+    benchmark(chunk_into_n, [1, 2, 3, 4, 5, 6, 7, 8, 9], 3)
diff --git a/tests/demo/test_arrow_usage.py b/tests/demo/test_arrow_usage.py
index ed88876..2a3bf2c 100644
--- a/tests/demo/test_arrow_usage.py
+++ b/tests/demo/test_arrow_usage.py
@@ -1,5 +1,6 @@
 import arrow
 from loguru import logger
+from pytest_benchmark.fixture import BenchmarkFixture
 
 from python_boilerplate.demo.arrow_usage import convert_time_zone, string_to_datetime
 
@@ -30,3 +31,7 @@ def test_convert_time_zone() -> None:
     assert converted is not None
     assert converted < now
     logger.info(f"Now: {now}, converted: {converted}")
+
+
+def test_string_to_datetime_benchmark(benchmark: BenchmarkFixture) -> None:
+    benchmark(string_to_datetime, "2022-01-01 15:15:00")
diff --git a/tests/demo/test_pydantic_usage.py b/tests/demo/test_pydantic_usage.py
index 6dbfead..df2aac3 100644
--- a/tests/demo/test_pydantic_usage.py
+++ b/tests/demo/test_pydantic_usage.py
@@ -3,6 +3,7 @@
 import pytest
 from loguru import logger
 from pydantic import ValidationError
+from pytest_benchmark.fixture import BenchmarkFixture
 
 from python_boilerplate.demo.pydantic_usage import User, UserDataClass
 
@@ -61,3 +62,19 @@ def test_initialize_user_with_dataclass() -> None:
     assert user.id == 1
     assert user.name == "John"
     logger.info(f"{user}")
+
+
+def create_instance() -> User:
+    return User.parse_obj({"id": 123, "name": "James"})
+
+
+def serialize_instance() -> str:
+    return User.parse_obj({"id": 123, "name": "James"}).json()
+
+
+def test_create_instance_benchmark(benchmark: BenchmarkFixture) -> None:
+    benchmark(create_instance)
+
+
+def test_serialize_instance_benchmark(benchmark: BenchmarkFixture) -> None:
+    benchmark(serialize_instance)
diff --git a/tests/template/test_html_template.py b/tests/template/test_html_template.py
index 58b9425..4f68828 100644
--- a/tests/template/test_html_template.py
+++ b/tests/template/test_html_template.py
@@ -2,6 +2,7 @@
 from typing import Any
 
 from loguru import logger
+from pytest_benchmark.fixture import BenchmarkFixture
 
 from python_boilerplate.template.html_template import render_template
 
@@ -33,3 +34,7 @@ def test_render_template_when_the_template_exists_then_no_raised_exception() ->
     assert "Hello reader, here is a table" in rendered
     assert "cid:a_picture_id" in rendered
     logger.info(f"Rendered template: \n{rendered}")
+
+
+def test_render_template_benchmark(benchmark: BenchmarkFixture) -> None:
+    benchmark(test_render_template_when_the_template_exists_then_no_raised_exception)