Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fevzi pine tree art #33

Merged
merged 11 commits into from
Jan 13, 2025
6 changes: 4 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ about: A template PR for code review with a checklist

- [ ] The function's name describes it's behavior
- [ ] The function's name matches the file name
- _It's ok to have extra helper functions if necessary, like with mergesort_
- [ ] The function has correct type annotations
- [ ] The function is not called in the function file
- [ ] The function is not called at the top level of the function file
- _Recursive solutions **can** call the function from **inside** the function body_

## Strategy

Expand All @@ -67,7 +69,7 @@ about: A template PR for code review with a checklist

### Don'ts

- [ ] The function's strategy _is not_ described in the documentation
- [ ] The function's strategy _is not_ described in any docstrings or tests
- [ ] Comments explain the _strategy_, **not** the _implementation_
- [ ] The function _does not_ have more comments than code
- If it does, consider finding a new strategy or a simpler implementation
Expand Down
54 changes: 54 additions & 0 deletions solutions/pine_tree_art.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
Module for generating and displaying ASCII art of a pine tree.

This module provides a function to create a visual representation of a pine tree
with customizable height and trunk dimensions.

Author: fevziismailsahin
Created: 01/09/2025
"""


def pine_tree_art(height: int = 10, trunk_width: int = 3, trunk_height: int = 3) -> str:
"""
Generate an ASCII art representation of a pine tree.

Parameters:
height (int): The height of the tree (default is 10).
trunk_width (int): The width of the tree trunk (default is 3).
trunk_height (int): The height of the tree trunk (default is 3).

Returns:
str: The generated ASCII art as a string.
"""

# Type checks
if (
not isinstance(height, int)
or not isinstance(trunk_width, int)
or not isinstance(trunk_height, int)
):
raise TypeError("Height, trunk_width, and trunk_height must be integers")

# Defensive assertions
if height <= 0:
raise ValueError("Height must be a positive integer")
if trunk_width <= 0:
raise ValueError("Trunk width must be a positive integer")
if trunk_height <= 0:
raise ValueError("Trunk height must be a positive integer")

# Create the foliage of the tree
tree = []
for i in range(height):
spaces = " " * (height - i - 1) # Add spaces for alignment (center the stars)
stars = "*" * (2 * i + 1) # Create the stars for the current level
tree.append(spaces + stars) # Append to tree list with correct alignment

# Create the trunk of the tree
trunk = " " * (height - trunk_width // 2 - 1) + "|" * trunk_width # Centered trunk
for _ in range(trunk_height):
tree.append(trunk)

# Return the tree as a single string with an extra newline at the end
return "\n".join(tree) + "\n"
84 changes: 84 additions & 0 deletions solutions/tests/test_pine_tree_art.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Unit test module for generating ASCII art of a pine tree.

Test categories:
- Standard cases: correct inputs for height, trunk_width, trunk_height;
- Edge cases;
- Defensive tests: wrong input types, assertions;

Created on 2025-01-11
Author: fevziismailsahin
"""

import unittest

from ..pine_tree_art import pine_tree_art


class TestPineTreeArt(unittest.TestCase):
"""Test suite for generating ASCII art of a pine tree."""

# Standard cases: correct inputs
def test_standard_case_1(self):
"""Test with typical valid inputs for height, trunk_width, trunk_height."""
expected_result = (
" *\n"
" ***\n"
" *****\n"
" *******\n"
" *********\n"
" ***********\n"
" *************\n"
" ***************\n"
" *****************\n"
"*******************\n"
" |||\n"
" |||\n"
" |||\n"
)
self.assertEqual(pine_tree_art(10, 3, 3), expected_result)

def test_standard_case_2(self):
"""Test with smaller tree height and trunk dimensions."""
expected_result = (
" *\n ***\n *****\n *******\n*********\n |||\n |||\n |||\n"
)
self.assertEqual(pine_tree_art(5, 3, 3), expected_result)

# Edge cases: testing zero or near-zero values
def test_zero_height(self):
"""Test when height is zero, which should raise a ValueError."""
with self.assertRaises(ValueError):
pine_tree_art(0, 3, 3)

def test_zero_trunk_width(self):
"""Test when trunk width is zero, which should raise a ValueError."""
with self.assertRaises(ValueError):
pine_tree_art(10, 0, 3)

def test_zero_trunk_height(self):
"""Test when trunk height is zero, which should raise a ValueError."""
with self.assertRaises(ValueError):
pine_tree_art(10, 3, 0)

# Defensive tests: wrong input types, assertions
def test_invalid_height_type(self):
"""Test when 'height' is not an integer, which should raise a TypeError."""
with self.assertRaises(TypeError):
pine_tree_art("ten", 3, 3)

def test_invalid_trunk_width_type(self):
"""Test when 'trunk_width' is not an integer, which should raise a TypeError."""
with self.assertRaises(TypeError):
pine_tree_art(10, "three", 3)

def test_invalid_trunk_height_type(self):
"""Test when 'trunk_height' is not an integer, which should raise a TypeError."""
with self.assertRaises(TypeError):
pine_tree_art(10, 3, "three")


if __name__ == "__main__":
unittest.main()
Loading