From 8dee5ca69afa8208abde02c82e3835159fb249e3 Mon Sep 17 00:00:00 2001 From: wc2184 Date: Mon, 27 Oct 2025 21:02:13 -0400 Subject: [PATCH 01/20] initial setup and add fortune function and empty function stubs --- pyproject.toml | 19 ++++++++++++ src/fortuneluckpredictor/__init__.py | 0 src/fortuneluckpredictor/__main__.py | 16 +++++++++++ src/fortuneluckpredictor/fortune.py | 43 ++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 pyproject.toml create mode 100644 src/fortuneluckpredictor/__init__.py create mode 100644 src/fortuneluckpredictor/__main__.py create mode 100644 src/fortuneluckpredictor/fortune.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..85af16e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "fortuneluckpredictor" +version = "0.0.1" +authors = [ + { name="Example Author", email="author@example.com" }, +] +description = "Fortune & luck predictor. Returns lucky numbers, fortunes, and horoscope-like results." +readme = "README.md" +requires-python = ">=3.9" +classifiers = [ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", +] +license = "MIT" +license-files = ["LICEN[CS]E*"] + +[project.urls] +Homepage = "https://github.com/swe-students-fall2025/3-python-package-team_boreal" +Issues = "https://github.com/swe-students-fall2025/3-python-package-team_boreal/issues" diff --git a/src/fortuneluckpredictor/__init__.py b/src/fortuneluckpredictor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/fortuneluckpredictor/__main__.py b/src/fortuneluckpredictor/__main__.py new file mode 100644 index 0000000..068a2ec --- /dev/null +++ b/src/fortuneluckpredictor/__main__.py @@ -0,0 +1,16 @@ +""" +Entry point for the fortuneluckpredictor package when run as a script. +""" + +from .fortune import fortune + + +def main() -> None: + """ + Fetch a fortune and print it to the console. + """ + print(fortune()) # in terminal: python -m fortuneluckpredictor will call this function + + +if __name__ == "__main__": + main() diff --git a/src/fortuneluckpredictor/fortune.py b/src/fortuneluckpredictor/fortune.py new file mode 100644 index 0000000..311b7ad --- /dev/null +++ b/src/fortuneluckpredictor/fortune.py @@ -0,0 +1,43 @@ +import random + + +def get_lucky_number(number_range: tuple[int, int] = (1, 100)) -> int: + pass + + +def fortune(cookie: bool = True) -> str: + fortunes = [ + "Your resume will land on the perfect Meta recruiter's desk this week.", + "A Meta engineer will soon endorse your skills and open a new door.", + "The next coding interview you take will feel like designing the future of social connections.", + "Your grind on system design is about to pay off with a Reality Labs breakthrough.", + "A friendly referral will unlock the Meta pipeline you've been eyeing.", + "An unexpected DM from a Meta recruiter will kickstart your big tech journey.", + "Your portfolio will impress a Meta hiring manager far more than you expect.", + "A well-timed leetcode streak will boost your confidence for the Meta onsite.", + "Soon you'll celebrate a Meta offer with your closest supporters.", + "The next recruiter call you accept will change the trajectory of your career in the metaverse.", + "A spontaneous trip will lead to a story you retell for years.", + "Your curiosity will uncover a hobby that becomes a passion.", + "A long-standing question will be answered in the most unexpected way.", + "You will reconnect with someone who inspires you to dream bigger.", + "Small daily habits will compound into a breakthrough moment.", + "A random compliment will brighten your day and boost your confidence.", + "Your next challenge will reveal strength you didn't know you had.", + "A creative idea will blossom into a project that excites others.", + "Soon you will realize you are exactly where you need to be.", + "An opportunity to help someone will come, and your kindness will be remembered.", + ] + return random.choice(fortunes) + + +def predict_day(day: str) -> str: + pass + + +def compatibility_score(name1: str, name2: str) -> str: + pass + + +def futurePrediction(name1: str) -> str: + pass From 55a8c3f8acf48ab29d4aad77844b654eaa45be62 Mon Sep 17 00:00:00 2001 From: Pranathi Chinthalapani Date: Mon, 27 Oct 2025 21:17:05 -0400 Subject: [PATCH 02/20] future predictions functions --- src/fortuneluckpredictor/__main__.py | 4 ++- src/fortuneluckpredictor/futurePredictions.py | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/fortuneluckpredictor/futurePredictions.py diff --git a/src/fortuneluckpredictor/__main__.py b/src/fortuneluckpredictor/__main__.py index 068a2ec..64563d2 100644 --- a/src/fortuneluckpredictor/__main__.py +++ b/src/fortuneluckpredictor/__main__.py @@ -3,13 +3,15 @@ """ from .fortune import fortune +from .futurePredictions import futurePrediction def main() -> None: """ Fetch a fortune and print it to the console. """ - print(fortune()) # in terminal: python -m fortuneluckpredictor will call this function + print(fortune()) + print(futurePrediction("Alice")) if __name__ == "__main__": diff --git a/src/fortuneluckpredictor/futurePredictions.py b/src/fortuneluckpredictor/futurePredictions.py new file mode 100644 index 0000000..6a6f372 --- /dev/null +++ b/src/fortuneluckpredictor/futurePredictions.py @@ -0,0 +1,32 @@ +import random + +def futurePrediction(name1: str) -> str: + careers = [ + "software engineer", "doctor", + "lawyer", "teacher", "artist", + "entrepreneur", "scientist", + "musician", "architect", "chef", + "engineer", "journalist", + "psychologist", "designer", "consultant", + "nurse", "researcher", "manager", + "analyst", "inventor" + ] + + marriage_ages = list(range(25, 40)) + kids_counts = list(range(0, 4)) + success_levels = ["very successful", "successful", + "somewhat successful", "moderately successful"] + + name = sum(ord(c) for c in name1) + + random.seed(name) + career = random.choice(careers) + marriage_age = random.choice(marriage_ages) + kids_count = random.choice(kids_counts) + success = random.choice(success_levels) + + kids_str = "kids" if kids_count != 1 else "kid" + kids_phrase = f"with {kids_count} {kids_str}" if kids_count > 0 else "with no kids" + + return f"{name1} will be a {career} and get married at {marriage_age} {kids_phrase} and you will be {success}" + From 7eb137033ce1ccbda00b8fd9c009628ce580f1a5 Mon Sep 17 00:00:00 2001 From: PranathiChin Date: Tue, 28 Oct 2025 14:08:28 -0400 Subject: [PATCH 03/20] testing something with account --- src/fortuneluckpredictor/futurePredictions.py | 33 +------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/src/fortuneluckpredictor/futurePredictions.py b/src/fortuneluckpredictor/futurePredictions.py index 6a6f372..30d74d2 100644 --- a/src/fortuneluckpredictor/futurePredictions.py +++ b/src/fortuneluckpredictor/futurePredictions.py @@ -1,32 +1 @@ -import random - -def futurePrediction(name1: str) -> str: - careers = [ - "software engineer", "doctor", - "lawyer", "teacher", "artist", - "entrepreneur", "scientist", - "musician", "architect", "chef", - "engineer", "journalist", - "psychologist", "designer", "consultant", - "nurse", "researcher", "manager", - "analyst", "inventor" - ] - - marriage_ages = list(range(25, 40)) - kids_counts = list(range(0, 4)) - success_levels = ["very successful", "successful", - "somewhat successful", "moderately successful"] - - name = sum(ord(c) for c in name1) - - random.seed(name) - career = random.choice(careers) - marriage_age = random.choice(marriage_ages) - kids_count = random.choice(kids_counts) - success = random.choice(success_levels) - - kids_str = "kids" if kids_count != 1 else "kid" - kids_phrase = f"with {kids_count} {kids_str}" if kids_count > 0 else "with no kids" - - return f"{name1} will be a {career} and get married at {marriage_age} {kids_phrase} and you will be {success}" - +test \ No newline at end of file From 86136a3bcfe85b743cda24611e94b0b52341fb0e Mon Sep 17 00:00:00 2001 From: PranathiChin Date: Tue, 28 Oct 2025 14:15:45 -0400 Subject: [PATCH 04/20] testing --- src/fortuneluckpredictor/futurePredictions.py | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/fortuneluckpredictor/futurePredictions.py b/src/fortuneluckpredictor/futurePredictions.py index 30d74d2..1add553 100644 --- a/src/fortuneluckpredictor/futurePredictions.py +++ b/src/fortuneluckpredictor/futurePredictions.py @@ -1 +1,33 @@ -test \ No newline at end of file +import random + +def futurePrediction(name1: str) -> str: + careers = [ + "software engineer", "doctor", + "lawyer", "teacher", "artist", + "entrepreneur", "scientist", + "musician", "architect", "chef", + "engineer", "journalist", + "psychologist", "designer", "consultant", + "nurse", "researcher", "manager", + "analyst", "inventor" + ] + + marriage_ages = list(range(25, 40)) + kids_counts = list(range(0, 4)) + success_levels = ["very successful", "successful", + "somewhat successful", "moderately successful"] + + name = sum(ord(c) for c in name1) + + random.seed(name) + career = random.choice(careers) + marriage_age = random.choice(marriage_ages) + kids_count = random.choice(kids_counts) + success = random.choice(success_levels) + + kids_str = "kids" if kids_count != 1 else "kid" + kids_phrase = f"with {kids_count} {kids_str}" if kids_count > 0 else "with no kids" + + return f"{name1} will be a {career} and get married at {marriage_age} {kids_phrase} and you will be {success}" + +testing = "testingSring" \ No newline at end of file From 695b4d8020abeedf5fe4b0db2ca6f27f39018992 Mon Sep 17 00:00:00 2001 From: PranathiChin Date: Tue, 28 Oct 2025 14:19:42 -0400 Subject: [PATCH 05/20] testing --- src/fortuneluckpredictor/futurePredictions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fortuneluckpredictor/futurePredictions.py b/src/fortuneluckpredictor/futurePredictions.py index 1add553..0fd7ce2 100644 --- a/src/fortuneluckpredictor/futurePredictions.py +++ b/src/fortuneluckpredictor/futurePredictions.py @@ -30,4 +30,4 @@ def futurePrediction(name1: str) -> str: return f"{name1} will be a {career} and get married at {marriage_age} {kids_phrase} and you will be {success}" -testing = "testingSring" \ No newline at end of file +testing = "testing" \ No newline at end of file From 9eed1b07f52f749e53686175f614b0449ec86e98 Mon Sep 17 00:00:00 2001 From: PranathiChin Date: Tue, 28 Oct 2025 14:22:06 -0400 Subject: [PATCH 06/20] reset --- src/fortuneluckpredictor/futurePredictions.py | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/fortuneluckpredictor/futurePredictions.py b/src/fortuneluckpredictor/futurePredictions.py index 0fd7ce2..b9b8268 100644 --- a/src/fortuneluckpredictor/futurePredictions.py +++ b/src/fortuneluckpredictor/futurePredictions.py @@ -1,33 +1 @@ -import random - -def futurePrediction(name1: str) -> str: - careers = [ - "software engineer", "doctor", - "lawyer", "teacher", "artist", - "entrepreneur", "scientist", - "musician", "architect", "chef", - "engineer", "journalist", - "psychologist", "designer", "consultant", - "nurse", "researcher", "manager", - "analyst", "inventor" - ] - - marriage_ages = list(range(25, 40)) - kids_counts = list(range(0, 4)) - success_levels = ["very successful", "successful", - "somewhat successful", "moderately successful"] - - name = sum(ord(c) for c in name1) - - random.seed(name) - career = random.choice(careers) - marriage_age = random.choice(marriage_ages) - kids_count = random.choice(kids_counts) - success = random.choice(success_levels) - - kids_str = "kids" if kids_count != 1 else "kid" - kids_phrase = f"with {kids_count} {kids_str}" if kids_count > 0 else "with no kids" - - return f"{name1} will be a {career} and get married at {marriage_age} {kids_phrase} and you will be {success}" - testing = "testing" \ No newline at end of file From d671704a2460bec5bfd445dd45db3dfb2185975c Mon Sep 17 00:00:00 2001 From: PranathiChin Date: Tue, 28 Oct 2025 14:24:34 -0400 Subject: [PATCH 07/20] adding future predictions function --- src/fortuneluckpredictor/futurePredictions.py | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/fortuneluckpredictor/futurePredictions.py b/src/fortuneluckpredictor/futurePredictions.py index b9b8268..e528830 100644 --- a/src/fortuneluckpredictor/futurePredictions.py +++ b/src/fortuneluckpredictor/futurePredictions.py @@ -1 +1,31 @@ -testing = "testing" \ No newline at end of file +import random + +def futurePrediction(name1: str) -> str: + careers = [ + "software engineer", "doctor", + "lawyer", "teacher", "artist", + "entrepreneur", "scientist", + "musician", "architect", "chef", + "engineer", "journalist", + "psychologist", "designer", "consultant", + "nurse", "researcher", "manager", + "analyst", "inventor" + ] + + marriage_ages = list(range(25, 40)) + kids_counts = list(range(0, 4)) + success_levels = ["very successful", "successful", + "somewhat successful", "moderately successful"] + + name = sum(ord(c) for c in name1) + + random.seed(name) + career = random.choice(careers) + marriage_age = random.choice(marriage_ages) + kids_count = random.choice(kids_counts) + success = random.choice(success_levels) + + kids_str = "kids" if kids_count != 1 else "kid" + kids_phrase = f"with {kids_count} {kids_str}" if kids_count > 0 else "with no kids" + + return f"{name1} will be a {career} and get married at {marriage_age} {kids_phrase} and you will be {success}" \ No newline at end of file From 9c1dad4d5a6c40f8220deb11a18c80f0cd1b1824 Mon Sep 17 00:00:00 2001 From: zz4206 Date: Tue, 28 Oct 2025 22:36:00 -0400 Subject: [PATCH 08/20] basic compatibility score --- Pipfile | 11 +++++++++++ src/fortuneluckpredictor/compatibility_score.py | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Pipfile create mode 100644 src/fortuneluckpredictor/compatibility_score.py diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..c398b0d --- /dev/null +++ b/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/src/fortuneluckpredictor/compatibility_score.py b/src/fortuneluckpredictor/compatibility_score.py new file mode 100644 index 0000000..2d55c4a --- /dev/null +++ b/src/fortuneluckpredictor/compatibility_score.py @@ -0,0 +1,17 @@ +import random + +def compatibility_score(name1: str, name2: str) -> str: + # number of vowels per name + v1 = 0 + v2 = 0 + vowels = ["a","e","i","o","u"] + for v in vowels: + c1 = name1.lower().count(v) + c2 = name2.lower().count(v) + if c1 > c2: + v1 += (c1 - c2) + else: + v2 += (c2 - c1) + + score = v1 + v2 + return \ No newline at end of file From 03b606865c2354eea8a68f8fe4768c1121d7fd03 Mon Sep 17 00:00:00 2001 From: zz4206 Date: Wed, 29 Oct 2025 00:48:21 -0400 Subject: [PATCH 09/20] compatibility score implemented --- src/fortuneluckpredictor/__main__.py | 2 ++ .../compatibility_score.py | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/fortuneluckpredictor/__main__.py b/src/fortuneluckpredictor/__main__.py index 64563d2..aa87dc1 100644 --- a/src/fortuneluckpredictor/__main__.py +++ b/src/fortuneluckpredictor/__main__.py @@ -4,6 +4,7 @@ from .fortune import fortune from .futurePredictions import futurePrediction +from .compatibility_score import compatibility_score def main() -> None: @@ -12,6 +13,7 @@ def main() -> None: """ print(fortune()) print(futurePrediction("Alice")) + print(compatibility_score("Ezio", "Altair")) if __name__ == "__main__": diff --git a/src/fortuneluckpredictor/compatibility_score.py b/src/fortuneluckpredictor/compatibility_score.py index 2d55c4a..ca37c4f 100644 --- a/src/fortuneluckpredictor/compatibility_score.py +++ b/src/fortuneluckpredictor/compatibility_score.py @@ -1,17 +1,25 @@ -import random - def compatibility_score(name1: str, name2: str) -> str: - # number of vowels per name - v1 = 0 - v2 = 0 - vowels = ["a","e","i","o","u"] + score = 0 + vowels = "aeiou" + c = [] # each vowel's count for v in vowels: c1 = name1.lower().count(v) c2 = name2.lower().count(v) - if c1 > c2: - v1 += (c1 - c2) - else: - v2 += (c2 - c1) + score = abs(c1 - c2) + c.append(score) + + while(len(c) > 1): + new_c = [] + for i in range(len(c) - 1): + new_c.append((c[i] + c[i+1]) % 10) + c = new_c + if score <= 2: + message = "Perfect match โ€” pure harmony! ๐Ÿ’ž" + elif score <= 4: + message = "You two vibe really well! โค๏ธ" + elif score <= 7: + message = "Thereโ€™s potential โ€” stay open and see where it goes! ๐ŸŒˆ" + else: + message = "Youโ€™ll meet someone wonderful who complements you perfectly! ๐Ÿ’ซ" - score = v1 + v2 - return \ No newline at end of file + return f"Compatibility score: {score}. {message}" \ No newline at end of file From a2551bde8d304dffcb133fcbddfcbc2e1fcfd268 Mon Sep 17 00:00:00 2001 From: SamRawdon Date: Thu, 30 Oct 2025 14:49:38 -0400 Subject: [PATCH 10/20] implemented lucky number --- src/fortuneluckpredictor/__main__.py | 3 +- src/fortuneluckpredictor/luckyNumber.py | 43 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/fortuneluckpredictor/luckyNumber.py diff --git a/src/fortuneluckpredictor/__main__.py b/src/fortuneluckpredictor/__main__.py index aa87dc1..6e34a33 100644 --- a/src/fortuneluckpredictor/__main__.py +++ b/src/fortuneluckpredictor/__main__.py @@ -5,7 +5,7 @@ from .fortune import fortune from .futurePredictions import futurePrediction from .compatibility_score import compatibility_score - +from .luckyNumber import get_lucky_number def main() -> None: """ @@ -14,6 +14,7 @@ def main() -> None: print(fortune()) print(futurePrediction("Alice")) print(compatibility_score("Ezio", "Altair")) + print(get_lucky_number()) if __name__ == "__main__": diff --git a/src/fortuneluckpredictor/luckyNumber.py b/src/fortuneluckpredictor/luckyNumber.py new file mode 100644 index 0000000..2a1055a --- /dev/null +++ b/src/fortuneluckpredictor/luckyNumber.py @@ -0,0 +1,43 @@ +import random +import math +from datetime import datetime + +try: + from zoneinfo import ZoneInfo + _tz = ZoneInfo("America/New_York") +except Exception: + _tz = None + +def get_lucky_number(range=(1, 100)): + a, b = range + if a > b: + a, b = b, a + nums = list(range(a, b + 1)) + + now = datetime.now(_tz) if _tz else datetime.now() + seed = int(now.strftime("%Y%m%d")) + r = random.Random(seed) + + day = now.day + month = now.month + wday = now.isoweekday() + hour = now.hour or 24 + minute = now.minute or 60 + digits_sum = sum(int(x) for x in now.strftime("%Y%m%d%H%M")) + + bases = [day, month, wday, hour, minute, digits_sum % (b - a + 1) or 1] + center = sum(bases) / len(bases) + scale = max(1.0, (b - a) / 8.0) + + weights = [] + for n in nums: + w = 1.0 + math.exp(-abs(n - center) / scale) + w += 0.25 * sum(1 for base in bases if base and n % base == 0) + last_digit = int(str(n)[-1]) + w += 0.2 if last_digit == day % 10 else 0.0 + w += 0.2 if last_digit == month % 10 else 0.0 + w += 0.1 * (str(day) in str(n)) + w += 0.1 * (str(month) in str(n)) + weights.append(w) + + return r.choices(nums, weights=weights, k=1)[0] \ No newline at end of file From 8fd350a12e359c0e609a6e6cd7e3eedd46a1eac5 Mon Sep 17 00:00:00 2001 From: zz4206 Date: Mon, 3 Nov 2025 03:04:12 -0500 Subject: [PATCH 11/20] some compatibility score tests --- Pipfile | 1 + Pipfile.lock | 126 ++++++++++++++++++++++++++++++ tests/__init__.py | 0 tests/test_compatibility_score.py | 42 ++++++++++ 4 files changed, 169 insertions(+) create mode 100644 Pipfile.lock create mode 100644 tests/__init__.py create mode 100644 tests/test_compatibility_score.py diff --git a/Pipfile b/Pipfile index c398b0d..6c56da5 100644 --- a/Pipfile +++ b/Pipfile @@ -4,6 +4,7 @@ verify_ssl = true name = "pypi" [packages] +pytest = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..c509268 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,126 @@ +{ + "_meta": { + "hash": { + "sha256": "20e1aad87698ead018f54bacfa6e7e1d5f1f0cae78c447d1465c006cbc99a583" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "exceptiongroup": { + "hashes": [ + "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", + "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88" + ], + "markers": "python_version < '3.11'", + "version": "==1.3.0" + }, + "iniconfig": { + "hashes": [ + "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", + "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" + ], + "markers": "python_version >= '3.10'", + "version": "==2.3.0" + }, + "packaging": { + "hashes": [ + "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", + "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" + ], + "markers": "python_version >= '3.8'", + "version": "==25.0" + }, + "pluggy": { + "hashes": [ + "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", + "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" + ], + "markers": "python_version >= '3.9'", + "version": "==1.6.0" + }, + "pygments": { + "hashes": [ + "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", + "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" + ], + "markers": "python_version >= '3.8'", + "version": "==2.19.2" + }, + "pytest": { + "hashes": [ + "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", + "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==8.4.2" + }, + "tomli": { + "hashes": [ + "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", + "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", + "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", + "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", + "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", + "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", + "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", + "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", + "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", + "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", + "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", + "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", + "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", + "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", + "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", + "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", + "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", + "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", + "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", + "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", + "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", + "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", + "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", + "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", + "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", + "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", + "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", + "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", + "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", + "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", + "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", + "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", + "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", + "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", + "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", + "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", + "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", + "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", + "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", + "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", + "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", + "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876" + ], + "markers": "python_version < '3.11'", + "version": "==2.3.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", + "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" + ], + "markers": "python_version < '3.13'", + "version": "==4.15.0" + } + }, + "develop": {} +} diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_compatibility_score.py b/tests/test_compatibility_score.py new file mode 100644 index 0000000..31c0c28 --- /dev/null +++ b/tests/test_compatibility_score.py @@ -0,0 +1,42 @@ +import re +import pytest +from fortuneluckpredictor import compatibility_score + + +@pytest.fixture +def sample_names(): + return [ + ("", ""), + ("Alice", "Alicia"), + ("Bob", "Bobby"), + ("Eve", "Adam"), + ("A", "E"), + ("Zoรซ", "Zoe"), + ] + + +def test_sanity_check(): + assert True + + +def test_compatibility_score_format_and_message(sample_names): + prefix_re = re.compile(r"^Compatibility score: \d+\. ") + messages = [ + "Perfect match โ€” pure harmony! ๐Ÿ’ž", + "You two vibe really well! โค๏ธ", + "Thereโ€™s potential โ€” stay open and see where it goes! ๐ŸŒˆ", + "Youโ€™ll meet someone wonderful who complements you perfectly! ๐Ÿ’ซ", + ] + + for n1, n2 in sample_names: + output = compatibility_score.compatibility_score(n1, n2) + assert isinstance(output, str) + assert prefix_re.match(output), f"output did not match prefix: {output!r}" + assert any(output.endswith(m) for m in messages), f"unexpected message in output: {output!r}" + + +def test_compatibility_score_is_deterministic(sample_names): + for n1, n2 in sample_names: + a = compatibility_score.compatibility_score(n1, n2) + b = compatibility_score.compatibility_score(n1, n2) + assert a == b \ No newline at end of file From be918ad7fb504b175eb70197799c3db482f20a05 Mon Sep 17 00:00:00 2001 From: zz4206 Date: Mon, 3 Nov 2025 03:46:11 -0500 Subject: [PATCH 12/20] compatibility score fixed after test --- .../compatibility_score.py | 20 ++++--- tests/test_compatibility_score.py | 52 ++++++++++--------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/fortuneluckpredictor/compatibility_score.py b/src/fortuneluckpredictor/compatibility_score.py index ca37c4f..1a16ca2 100644 --- a/src/fortuneluckpredictor/compatibility_score.py +++ b/src/fortuneluckpredictor/compatibility_score.py @@ -2,24 +2,30 @@ def compatibility_score(name1: str, name2: str) -> str: score = 0 vowels = "aeiou" c = [] # each vowel's count + n1 = name1.lower() + n2 = name2.lower() for v in vowels: - c1 = name1.lower().count(v) - c2 = name2.lower().count(v) - score = abs(c1 - c2) - c.append(score) - + c1 = n1.count(v) + c2 = n2.count(v) + n = abs(c1 - c2) + c.append(n) + + # Add vowel counts next to each other together until one digit remains while(len(c) > 1): new_c = [] for i in range(len(c) - 1): new_c.append((c[i] + c[i+1]) % 10) c = new_c + + score = c[0] + # compatibility message based on final score if score <= 2: message = "Perfect match โ€” pure harmony! ๐Ÿ’ž" elif score <= 4: message = "You two vibe really well! โค๏ธ" elif score <= 7: - message = "Thereโ€™s potential โ€” stay open and see where it goes! ๐ŸŒˆ" + message = "There's potential โ€” stay open and see where it goes! ๐ŸŒˆ" else: - message = "Youโ€™ll meet someone wonderful who complements you perfectly! ๐Ÿ’ซ" + message = "You'll meet someone wonderful who complements you perfectly! ๐Ÿ’ซ" return f"Compatibility score: {score}. {message}" \ No newline at end of file diff --git a/tests/test_compatibility_score.py b/tests/test_compatibility_score.py index 31c0c28..06dc265 100644 --- a/tests/test_compatibility_score.py +++ b/tests/test_compatibility_score.py @@ -1,42 +1,46 @@ -import re import pytest from fortuneluckpredictor import compatibility_score - +# Sample names for testing @pytest.fixture def sample_names(): return [ - ("", ""), - ("Alice", "Alicia"), - ("Bob", "Bobby"), - ("Eve", "Adam"), - ("A", "E"), - ("Zoรซ", "Zoe"), + ("", "", "Compatibility score: 0. Perfect match โ€” pure harmony! ๐Ÿ’ž"), + ("hello", "hi", "Compatibility score: 4. You two vibe really well! โค๏ธ"), + ("moon", "train", "Compatibility score: 5. There's potential โ€” stay open and see where it goes! ๐ŸŒˆ"), + ("bee", "pool", "Compatibility score: 6. There's potential โ€” stay open and see where it goes! ๐ŸŒˆ"), + ("aaa", "eee", "Compatibility score: 5. There's potential โ€” stay open and see where it goes! ๐ŸŒˆ"), + ("hello", "hello", "Compatibility score: 0. Perfect match โ€” pure harmony! ๐Ÿ’ž"), + ("Michael", "Michelle", "Compatibility score: 5. There's potential โ€” stay open and see where it goes! ๐ŸŒˆ"), + ("James", "Emma", "Compatibility score: 0. Perfect match โ€” pure harmony! ๐Ÿ’ž"), + ("Isabella", "Alexander", "Compatibility score: 0. Perfect match โ€” pure harmony! ๐Ÿ’ž"), + ("William", "Olivia", "Compatibility score: 4. You two vibe really well! โค๏ธ"), + ("Sophia", "Daniel", "Compatibility score: 8. You'll meet someone wonderful who complements you perfectly! ๐Ÿ’ซ"), + ("Emily", "David", "Compatibility score: 5. There's potential โ€” stay open and see where it goes! ๐ŸŒˆ"), + ("Ethan", "Ava", "Compatibility score: 5. There's potential โ€” stay open and see where it goes! ๐ŸŒˆ"), + ("Benjamin", "Charlotte", "Compatibility score: 0. Perfect match โ€” pure harmony! ๐Ÿ’ž"), + ("Mia", "Lucas", "Compatibility score: 7. There's potential โ€” stay open and see where it goes! ๐ŸŒˆ") ] - +# Test sanity check def test_sanity_check(): assert True - -def test_compatibility_score_format_and_message(sample_names): - prefix_re = re.compile(r"^Compatibility score: \d+\. ") - messages = [ - "Perfect match โ€” pure harmony! ๐Ÿ’ž", - "You two vibe really well! โค๏ธ", - "Thereโ€™s potential โ€” stay open and see where it goes! ๐ŸŒˆ", - "Youโ€™ll meet someone wonderful who complements you perfectly! ๐Ÿ’ซ", - ] - - for n1, n2 in sample_names: +# Test that output is a string +def test_format(sample_names): + for n1, n2, _ in sample_names: output = compatibility_score.compatibility_score(n1, n2) assert isinstance(output, str) - assert prefix_re.match(output), f"output did not match prefix: {output!r}" - assert any(output.endswith(m) for m in messages), f"unexpected message in output: {output!r}" +# Test exact outputs for sample names +def test_exact_match(sample_names): + for n1, n2, expected in sample_names: + actual = compatibility_score.compatibility_score(n1, n2) + assert actual == expected, f"for ({n1},{n2}) expected {expected!r} but got {actual!r}" -def test_compatibility_score_is_deterministic(sample_names): - for n1, n2 in sample_names: +# Test that the compatibility score is same for same inputs +def test_consistent_output(sample_names): + for n1, n2, _ in sample_names: a = compatibility_score.compatibility_score(n1, n2) b = compatibility_score.compatibility_score(n1, n2) assert a == b \ No newline at end of file From e55fc09eb9536032e8f1fe1f532414ae9c3e347b Mon Sep 17 00:00:00 2001 From: Deng-Hanjun Date: Mon, 3 Nov 2025 15:15:42 -0500 Subject: [PATCH 13/20] Implement predict_day --- src/fortuneluckpredictor/predictDay.py | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/fortuneluckpredictor/predictDay.py diff --git a/src/fortuneluckpredictor/predictDay.py b/src/fortuneluckpredictor/predictDay.py new file mode 100644 index 0000000..f275f18 --- /dev/null +++ b/src/fortuneluckpredictor/predictDay.py @@ -0,0 +1,55 @@ +from .fortune import fortune + +# Each day has its own "theme" or message style +DAY_MESSAGES = { + "monday": "Fresh energy fills your week โ€” set your intentions high.", + "tuesday": "Progress is building; stay focused and take bold steps.", + "wednesday": "Midweek clarity brings productive breakthroughs.", + "thursday": "Youโ€™re almost at the finish line โ€” stay sharp and consistent.", + "friday": "Celebrate your wins, no matter how small!", + "saturday": "Recharge your creative battery โ€” inspiration awaits.", + "sunday": "Plan lightly and dream big for the week ahead.", +} + +# Support abbreviations (Mon, Tue, etc.) +DAY_ALIASES = { + "mon": "monday", + "tue": "tuesday", "tues": "tuesday", + "wed": "wednesday", + "thu": "thursday", "thur": "thursday", "thurs": "thursday", + "fri": "friday", + "sat": "saturday", + "sun": "sunday", +} + +def predict_day(day: str) -> str: + """ + Predict your day's vibe and include a random fortune. + + Args: + day (str): Name of the day, case-insensitive (e.g. "Monday", "mon") + + Returns: + str: A string combining the day's message and a random fortune. + + Example: + >>> predict_day("Monday") + 'Monday: Fresh energy fills your week โ€” set your intentions high. Fortune: Your resume will land on the perfect Meta recruiterโ€™s desk this week.' + """ + if not day or not day.strip(): + raise ValueError("Day must be a non-empty string.") + + day_lower = day.strip().lower() + + # Resolve abbreviations + if day_lower in DAY_MESSAGES: + key = day_lower + elif day_lower in DAY_ALIASES: + key = DAY_ALIASES[day_lower] + else: + raise ValueError(f"Unrecognized day name: {day}") + + message = DAY_MESSAGES[key] + fortune_text = fortune() + + return f"{day.capitalize()}: {message} Fortune: {fortune_text}" From 3ea466f76a7f992b12046c37534f0ed458eb4c69 Mon Sep 17 00:00:00 2001 From: zz4206 Date: Mon, 3 Nov 2025 21:36:13 -0500 Subject: [PATCH 14/20] add menu to main --- src/fortuneluckpredictor/__main__.py | 56 ++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/src/fortuneluckpredictor/__main__.py b/src/fortuneluckpredictor/__main__.py index 6e34a33..201b6e9 100644 --- a/src/fortuneluckpredictor/__main__.py +++ b/src/fortuneluckpredictor/__main__.py @@ -1,21 +1,47 @@ -""" -Entry point for the fortuneluckpredictor package when run as a script. -""" - -from .fortune import fortune -from .futurePredictions import futurePrediction -from .compatibility_score import compatibility_score -from .luckyNumber import get_lucky_number +from fortune import fortune +from futurePredictions import futurePrediction +from compatibility_score import compatibility_score +from luckyNumber import get_lucky_number +from predictDay import predict_day def main() -> None: - """ - Fetch a fortune and print it to the console. - """ - print(fortune()) - print(futurePrediction("Alice")) - print(compatibility_score("Ezio", "Altair")) - print(get_lucky_number()) + while True: + print("\nโœจ๐Ÿ”ฎโœจ==============================โœจ๐Ÿ”ฎโœจ") + print(" Welcome to Fortune Luck Predictor! ") + print("โœจ๐Ÿ”ฎโœจ==============================โœจ๐Ÿ”ฎโœจ") + print(" (ใฅ๏ฝกโ—•โ€ฟโ€ฟโ—•๏ฝก)ใฅ โœจ ๐Ÿง™โ€โ™‚๏ธ ๐Ÿ€ ๐Ÿฆ„ ") + print("1. Get your fortune โœจ") + print("2. Predict your future ๐Ÿ”ฎ") + print("3. Predict your day โ˜€๏ธ") + print("4. Compatibility score ๐Ÿ’ž") + print("5. Get your lucky number ๐Ÿ€") + print("6. Exit ๐Ÿšช") + choice = input("Choose an option (1-6): ").strip() + if choice == "1": + print("\nYour fortune:") + print(fortune()) + elif choice == "2": + name = input("Enter your name: ").strip() + print(futurePrediction(name)) + elif choice == "3": + day = input("Enter a day of the week: ").strip() + try: + print(predict_day(day)) + except Exception as e: + print(f"Error: {e}") + elif choice == "4": + name1 = input("Enter the first name: ").strip() + name2 = input("Enter the second name: ").strip() + print(compatibility_score(name1, name2)) + elif choice == "5": + print("Your lucky number:") + print(get_lucky_number()) + elif choice == "6": + print("Goodbye! โœจ") + break + else: + print("Invalid choice. Please enter a number from 1 to 6.") if __name__ == "__main__": main() From 41e508f70be1a6caac67598b00cae680448c1a4c Mon Sep 17 00:00:00 2001 From: zz4206 Date: Mon, 3 Nov 2025 21:52:42 -0500 Subject: [PATCH 15/20] fixed luckynumber and main --- src/fortuneluckpredictor/__main__.py | 33 ++++++++++++++++--------- src/fortuneluckpredictor/luckyNumber.py | 4 +-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/fortuneluckpredictor/__main__.py b/src/fortuneluckpredictor/__main__.py index 201b6e9..6aedc31 100644 --- a/src/fortuneluckpredictor/__main__.py +++ b/src/fortuneluckpredictor/__main__.py @@ -1,15 +1,17 @@ -from fortune import fortune -from futurePredictions import futurePrediction -from compatibility_score import compatibility_score -from luckyNumber import get_lucky_number -from predictDay import predict_day +from .fortune import fortune +from .futurePredictions import futurePrediction +from .compatibility_score import compatibility_score +from .luckyNumber import get_lucky_number +from .predictDay import predict_day def main() -> None: + + print("\nโœจ๐Ÿ”ฎโœจ==============================โœจ๐Ÿ”ฎโœจ") + print(" Welcome to Fortune Luck Predictor! ") + print("โœจ๐Ÿ”ฎโœจ==============================โœจ๐Ÿ”ฎโœจ") + print(" (ใฅ๏ฝกโ—•โ€ฟโ€ฟโ—•๏ฝก)ใฅ โœจ ๐Ÿง™โ€โ™‚๏ธ ๐Ÿ€ ๐Ÿฆ„ ") + while True: - print("\nโœจ๐Ÿ”ฎโœจ==============================โœจ๐Ÿ”ฎโœจ") - print(" Welcome to Fortune Luck Predictor! ") - print("โœจ๐Ÿ”ฎโœจ==============================โœจ๐Ÿ”ฎโœจ") - print(" (ใฅ๏ฝกโ—•โ€ฟโ€ฟโ—•๏ฝก)ใฅ โœจ ๐Ÿง™โ€โ™‚๏ธ ๐Ÿ€ ๐Ÿฆ„ ") print("1. Get your fortune โœจ") print("2. Predict your future ๐Ÿ”ฎ") print("3. Predict your day โ˜€๏ธ") @@ -23,17 +25,17 @@ def main() -> None: print(fortune()) elif choice == "2": name = input("Enter your name: ").strip() - print(futurePrediction(name)) + print("\n" + futurePrediction(name)) elif choice == "3": day = input("Enter a day of the week: ").strip() try: - print(predict_day(day)) + print("\n" + predict_day(day)) except Exception as e: print(f"Error: {e}") elif choice == "4": name1 = input("Enter the first name: ").strip() name2 = input("Enter the second name: ").strip() - print(compatibility_score(name1, name2)) + print("\n" + compatibility_score(name1, name2)) elif choice == "5": print("Your lucky number:") print(get_lucky_number()) @@ -42,6 +44,13 @@ def main() -> None: break else: print("Invalid choice. Please enter a number from 1 to 6.") + + continue_prompt = input("\nWould you like to try another option? (yes/no): ").strip().lower() + if continue_prompt not in ('yes', 'y'): + print("Goodbye! โœจ") + break + + print("\n") if __name__ == "__main__": main() diff --git a/src/fortuneluckpredictor/luckyNumber.py b/src/fortuneluckpredictor/luckyNumber.py index 2a1055a..b9ae762 100644 --- a/src/fortuneluckpredictor/luckyNumber.py +++ b/src/fortuneluckpredictor/luckyNumber.py @@ -8,8 +8,8 @@ except Exception: _tz = None -def get_lucky_number(range=(1, 100)): - a, b = range +def get_lucky_number(r=(1, 100)): + a, b = r if a > b: a, b = b, a nums = list(range(a, b + 1)) From 544441a87900aeb9e87d8fa53b8a473d5d241bb2 Mon Sep 17 00:00:00 2001 From: Deng-Hanjun Date: Mon, 3 Nov 2025 23:43:49 -0500 Subject: [PATCH 16/20] Update predictDay, fortune, and main --- src/fortuneluckpredictor/__main__.py | 14 ++++---- src/fortuneluckpredictor/fortune.py | 25 ++++---------- src/fortuneluckpredictor/predictDay.py | 47 ++++++++++++++------------ 3 files changed, 38 insertions(+), 48 deletions(-) diff --git a/src/fortuneluckpredictor/__main__.py b/src/fortuneluckpredictor/__main__.py index 201b6e9..7bb8ee7 100644 --- a/src/fortuneluckpredictor/__main__.py +++ b/src/fortuneluckpredictor/__main__.py @@ -1,8 +1,8 @@ -from fortune import fortune -from futurePredictions import futurePrediction -from compatibility_score import compatibility_score -from luckyNumber import get_lucky_number -from predictDay import predict_day +from .fortune import get_fortune +from .futurePredictions import futurePrediction +from .compatibility_score import compatibility_score +from .luckyNumber import get_lucky_number +from .predictDay import predict_day def main() -> None: while True: @@ -20,14 +20,14 @@ def main() -> None: if choice == "1": print("\nYour fortune:") - print(fortune()) + print(get_fortune()) elif choice == "2": name = input("Enter your name: ").strip() print(futurePrediction(name)) elif choice == "3": day = input("Enter a day of the week: ").strip() try: - print(predict_day(day)) + print(predict_day(day or None)) except Exception as e: print(f"Error: {e}") elif choice == "4": diff --git a/src/fortuneluckpredictor/fortune.py b/src/fortuneluckpredictor/fortune.py index 311b7ad..d5d64e4 100644 --- a/src/fortuneluckpredictor/fortune.py +++ b/src/fortuneluckpredictor/fortune.py @@ -1,12 +1,6 @@ import random - -def get_lucky_number(number_range: tuple[int, int] = (1, 100)) -> int: - pass - - -def fortune(cookie: bool = True) -> str: - fortunes = [ +fortunes = [ "Your resume will land on the perfect Meta recruiter's desk this week.", "A Meta engineer will soon endorse your skills and open a new door.", "The next coding interview you take will feel like designing the future of social connections.", @@ -28,16 +22,9 @@ def fortune(cookie: bool = True) -> str: "Soon you will realize you are exactly where you need to be.", "An opportunity to help someone will come, and your kindness will be remembered.", ] - return random.choice(fortunes) - - -def predict_day(day: str) -> str: - pass - - -def compatibility_score(name1: str, name2: str) -> str: - pass - -def futurePrediction(name1: str) -> str: - pass +def get_fortune(cookie: bool = True) -> str: + if cookie: + return f"๐Ÿช {random.choice(fortunes)}" + else: + return random.choice(fortunes) \ No newline at end of file diff --git a/src/fortuneluckpredictor/predictDay.py b/src/fortuneluckpredictor/predictDay.py index f275f18..8372172 100644 --- a/src/fortuneluckpredictor/predictDay.py +++ b/src/fortuneluckpredictor/predictDay.py @@ -1,4 +1,6 @@ -from .fortune import fortune +from .fortune import fortunes +import random +from datetime import datetime # Each day has its own "theme" or message style DAY_MESSAGES = { @@ -22,34 +24,35 @@ "sun": "sunday", } -def predict_day(day: str) -> str: +def predict_day(day: str | None = None) -> str: """ - Predict your day's vibe and include a random fortune. + Predicts a fortune and daily message for a given day. + If no day is provided, uses the current weekday. Args: - day (str): Name of the day, case-insensitive (e.g. "Monday", "mon") + day (str | None): The name or abbreviation of a day (e.g., "Mon", "Monday"). + If None, uses today's weekday. Returns: - str: A string combining the day's message and a random fortune. - - Example: - >>> predict_day("Monday") - 'Monday: Fresh energy fills your week โ€” set your intentions high. Fortune: Your resume will land on the perfect Meta recruiterโ€™s desk this week.' + str: A formatted string with the day's message and a fortune. """ - if not day or not day.strip(): - raise ValueError("Day must be a non-empty string.") - - day_lower = day.strip().lower() + # If no day provided, use today's day name + if not day: + day = datetime.now().strftime("%A") - # Resolve abbreviations - if day_lower in DAY_MESSAGES: - key = day_lower - elif day_lower in DAY_ALIASES: - key = DAY_ALIASES[day_lower] - else: - raise ValueError(f"Unrecognized day name: {day}") + d = day.strip().lower() + # Normalize to full day name + key = d if d in DAY_MESSAGES else DAY_ALIASES.get(d) + if not key: + raise ValueError(f"Unrecognized day name: '{day}'") message = DAY_MESSAGES[key] - fortune_text = fortune() - return f"{day.capitalize()}: {message} Fortune: {fortune_text}" + # Create a deterministic fortune based on today's date and day name + today = datetime.now().strftime("%Y-%m-%d") + seed_value = hash(today + key) % (2**32) + rng = random.Random(seed_value) + fortune_text = rng.choice(fortunes) + + # Format nicely + return f"{day.capitalize()}: {message} Fortune: {fortune_text}" \ No newline at end of file From 77fff2cc962e00987ce62c8c6a50b0457ff91f8b Mon Sep 17 00:00:00 2001 From: SamRawdon Date: Tue, 4 Nov 2025 00:44:22 -0500 Subject: [PATCH 17/20] added lucky number testst --- tests/test_lucky_number.py | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/test_lucky_number.py diff --git a/tests/test_lucky_number.py b/tests/test_lucky_number.py new file mode 100644 index 0000000..d7f822a --- /dev/null +++ b/tests/test_lucky_number.py @@ -0,0 +1,66 @@ +import pytest +import math +from fortuneluckpredictor import get_lucky_number + +@pytest.fixture +def sample_ranges(): + return [ + (1, 100), + (50, 60), + (100, 1), # reversed range + (7, 7), # single-number range + ] + +def test_sanity_check(): + assert True + +# Range check +def test_output_type_and_bounds(sample_ranges): + """Check that output is an integer within the expected bounds.""" + for r in sample_ranges: + result = get_lucky_number.get_lucky_number(r) + assert isinstance(result, int) + a, b = r + lo, hi = (a, b) if a <= b else (b, a) + assert lo <= result <= hi, f"{result} not in {lo}-{hi}" + +# Returns same number when given same time +def test_consistent_same_seed(monkeypatch): + """When called within the same minute, output should be stable.""" + from datetime import datetime + class FixedTime(datetime): + @classmethod + def now(cls, tz=None): + return datetime(2025, 11, 3, 14, 45) + monkeypatch.setattr(get_lucky_number, "datetime", FixedTime) + first = get_lucky_number.get_lucky_number((1, 100)) + second = get_lucky_number.get_lucky_number((1, 100)) + assert first == second + +# Returns different numbers at different times +def test_distribution_varies_over_time(monkeypatch): + """Different times should usually yield different lucky numbers.""" + from datetime import datetime + class TimeVariant(datetime): + @classmethod + def now(cls, tz=None): + # alternate between two moments + if hasattr(cls, "_toggle"): + del cls._toggle + return datetime(2025, 11, 3, 14, 46) + else: + cls._toggle = True + return datetime(2025, 11, 2, 14, 45) + monkeypatch.setattr(get_lucky_number, "datetime", TimeVariant) + n1 = get_lucky_number.get_lucky_number((1, 100)) + n2 = get_lucky_number.get_lucky_number((1, 100)) + assert n1 != n2, f"Expected different results across distinct datetimes ({n1} == {n2})" + +def test_single_value_range(): + """If range has only one number, that number must be returned.""" + assert get_lucky_number.get_lucky_number((42, 42)) == 42 + +def test_reversed_range_handled(): + """Swapped a,b should still produce valid result.""" + val = get_lucky_number.get_lucky_number((100, 1)) + assert 1 <= val <= 100 \ No newline at end of file From 7eec4fcb4108e71f1bde8e79cefdfacacda371d3 Mon Sep 17 00:00:00 2001 From: zz4206 Date: Tue, 4 Nov 2025 00:51:14 -0500 Subject: [PATCH 18/20] fix tests --- Pipfile | 2 + Pipfile.lock | 113 +++++++++++++++++++++++++++++- tests/test_compatibility_score.py | 2 +- tests/test_lucky_number.py | 20 +++--- 4 files changed, 125 insertions(+), 12 deletions(-) diff --git a/Pipfile b/Pipfile index 6c56da5..8b211e3 100644 --- a/Pipfile +++ b/Pipfile @@ -5,6 +5,8 @@ name = "pypi" [packages] pytest = "*" +coverage = "*" +pytest-cov = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index c509268..41a6443 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "20e1aad87698ead018f54bacfa6e7e1d5f1f0cae78c447d1465c006cbc99a583" + "sha256": "86787bc83b48d0f9ff34a488f1dfd698c217e795b3018235f3a82cc26a24efd4" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,108 @@ ] }, "default": { + "coverage": { + "extras": [ + "toml" + ], + "hashes": [ + "sha256:037b2d064c2f8cc8716fe4d39cb705779af3fbf1ba318dc96a1af858888c7bb5", + "sha256:05791e528a18f7072bf5998ba772fe29db4da1234c45c2087866b5ba4dea710e", + "sha256:0d7f0616c557cbc3d1c2090334eddcbb70e1ae3a40b07222d62b3aa47f608fab", + "sha256:0efa742f431529699712b92ecdf22de8ff198df41e43aeaaadf69973eb93f17a", + "sha256:10ad04ac3a122048688387828b4537bc9cf60c0bf4869c1e9989c46e45690b82", + "sha256:167bd504ac1ca2af7ff3b81d245dfea0292c5032ebef9d66cc08a7d28c1b8050", + "sha256:16ce17ceb5d211f320b62df002fa7016b7442ea0fd260c11cec8ce7730954893", + "sha256:214b622259dd0cf435f10241f1333d32caa64dbc27f8790ab693428a141723de", + "sha256:24d6f3128f1b2d20d84b24f4074475457faedc3d4613a7e66b5e769939c7d969", + "sha256:258d9967520cca899695d4eb7ea38be03f06951d6ca2f21fb48b1235f791e601", + "sha256:269bfe913b7d5be12ab13a95f3a76da23cf147be7fa043933320ba5625f0a8de", + "sha256:2727d47fce3ee2bac648528e41455d1b0c46395a087a229deac75e9f88ba5a05", + "sha256:314c24e700d7027ae3ab0d95fbf8d53544fca1f20345fd30cd219b737c6e58d3", + "sha256:3d4ba9a449e9364a936a27322b20d32d8b166553bfe63059bd21527e681e2fad", + "sha256:3d4ed4de17e692ba6415b0587bc7f12bc80915031fc9db46a23ce70fc88c9841", + "sha256:3d58ecaa865c5b9fa56e35efc51d1014d4c0d22838815b9fce57a27dd9576847", + "sha256:4036cc9c7983a2b1f2556d574d2eb2154ac6ed55114761685657e38782b23f52", + "sha256:424538266794db2861db4922b05d729ade0940ee69dcf0591ce8f69784db0e11", + "sha256:4b7589765348d78fb4e5fb6ea35d07564e387da2fc5efff62e0222971f155f68", + "sha256:4c1eeb3fb8eb9e0190bebafd0462936f75717687117339f708f395fe455acc73", + "sha256:4d3ffa07a08657306cd2215b0da53761c4d73cb54d9143b9303a6481ec0cd415", + "sha256:5693e57a065760dcbeb292d60cc4d0231a6d4b6b6f6a3191561e1d5e8820b745", + "sha256:587c38849b853b157706407e9ebdca8fd12f45869edb56defbef2daa5fb0812b", + "sha256:596763d2f9a0ee7eec6e643e29660def2eef297e1de0d334c78c08706f1cb785", + "sha256:59a6e5a265f7cfc05f76e3bb53eca2e0dfe90f05e07e849930fecd6abb8f40b4", + "sha256:5a03eaf7ec24078ad64a07f02e30060aaf22b91dedf31a6b24d0d98d2bba7f48", + "sha256:5ef83b107f50db3f9ae40f69e34b3bd9337456c5a7fe3461c7abf8b75dd666a2", + "sha256:630d0bd7a293ad2fc8b4b94e5758c8b2536fdf36c05f1681270203e463cbfa9b", + "sha256:695340f698a5f56f795b2836abe6fb576e7c53d48cd155ad2f80fd24bc63a040", + "sha256:6fbcee1a8f056af07ecd344482f711f563a9eb1c2cad192e87df00338ec3cdb0", + "sha256:7161edd3426c8d19bdccde7d49e6f27f748f3c31cc350c5de7c633fea445d866", + "sha256:73feb83bb41c32811973b8565f3705caf01d928d972b72042b44e97c71fd70d1", + "sha256:765c0bc8fe46f48e341ef737c91c715bd2a53a12792592296a095f0c237e09cf", + "sha256:7ab934dd13b1c5e94b692b1e01bd87e4488cb746e3a50f798cb9464fd128374b", + "sha256:7db53b5cdd2917b6eaadd0b1251cf4e7d96f4a8d24e174bdbdf2f65b5ea7994d", + "sha256:80027673e9d0bd6aef86134b0771845e2da85755cf686e7c7c59566cf5a89115", + "sha256:81b335f03ba67309a95210caf3eb43bd6fe75a4e22ba653ef97b4696c56c7ec2", + "sha256:865965bf955d92790f1facd64fe7ff73551bd2c1e7e6b26443934e9701ba30b9", + "sha256:8badf70446042553a773547a61fecaa734b55dc738cacf20c56ab04b77425e43", + "sha256:8c934bd088eed6174210942761e38ee81d28c46de0132ebb1801dbe36a390dcc", + "sha256:9516add7256b6713ec08359b7b05aeff8850c98d357784c7205b2e60aa2513fa", + "sha256:9c49e77811cf9d024b95faf86c3f059b11c0c9be0b0d61bc598f453703bd6fd1", + "sha256:9cbabd8f4d0d3dc571d77ae5bdbfa6afe5061e679a9d74b6797c48d143307088", + "sha256:9ed43fa22c6436f7957df036331f8fe4efa7af132054e1844918866cd228af6c", + "sha256:a09c1211959903a479e389685b7feb8a17f59ec5a4ef9afde7650bd5eabc2777", + "sha256:a1839d08406e4cba2953dcc0ffb312252f14d7c4c96919f70167611f4dee2623", + "sha256:a386c1061bf98e7ea4758e4313c0ab5ecf57af341ef0f43a0bf26c2477b5c268", + "sha256:a3b6a5f8b2524fd6c1066bc85bfd97e78709bb5e37b5b94911a6506b65f47186", + "sha256:a3d0e2087dba64c86a6b254f43e12d264b636a39e88c5cc0a01a7c71bcfdab7e", + "sha256:a61e37a403a778e2cda2a6a39abcc895f1d984071942a41074b5c7ee31642007", + "sha256:aef1747ede4bd8ca9cfc04cc3011516500c6891f1b33a94add3253f6f876b7b7", + "sha256:b56efee146c98dbf2cf5cffc61b9829d1e94442df4d7398b26892a53992d3547", + "sha256:b5c2705afa83f49bd91962a4094b6b082f94aef7626365ab3f8f4bd159c5acf3", + "sha256:b679e171f1c104a5668550ada700e3c4937110dbdd153b7ef9055c4f1a1ee3cc", + "sha256:b971bdefdd75096163dd4261c74be813c4508477e39ff7b92191dea19f24cd37", + "sha256:bab7ec4bb501743edc63609320aaec8cd9188b396354f482f4de4d40a9d10721", + "sha256:bc1fbea96343b53f65d5351d8fd3b34fd415a2670d7c300b06d3e14a5af4f552", + "sha256:c6f31f281012235ad08f9a560976cc2fc9c95c17604ff3ab20120fe480169bca", + "sha256:c770885b28fb399aaf2a65bbd1c12bf6f307ffd112d6a76c5231a94276f0c497", + "sha256:c79cae102bb3b1801e2ef1511fb50e91ec83a1ce466b2c7c25010d884336de46", + "sha256:c9f08ea03114a637dab06cedb2e914da9dc67fa52c6015c018ff43fdde25b9c2", + "sha256:ca61691ba8c5b6797deb221a0d09d7470364733ea9c69425a640f1f01b7c5bf0", + "sha256:cacb29f420cfeb9283b803263c3b9a068924474ff19ca126ba9103e1278dfa44", + "sha256:cc3f49e65ea6e0d5d9bd60368684fe52a704d46f9e7fc413918f18d046ec40e1", + "sha256:cdbcd376716d6b7fbfeedd687a6c4be019c5a5671b35f804ba76a4c0a778cba4", + "sha256:ce37f215223af94ef0f75ac68ea096f9f8e8c8ec7d6e8c346ee45c0d363f0479", + "sha256:ce9f3bde4e9b031eaf1eb61df95c1401427029ea1bfddb8621c1161dcb0fa02e", + "sha256:cee6291bb4fed184f1c2b663606a115c743df98a537c969c3c64b49989da96c2", + "sha256:cf9e6ff4ca908ca15c157c409d608da77a56a09877b97c889b98fb2c32b6465e", + "sha256:d06f4fc7acf3cabd6d74941d53329e06bab00a8fe10e4df2714f0b134bfc64ef", + "sha256:d66c0104aec3b75e5fd897e7940188ea1892ca1d0235316bf89286d6a22568c0", + "sha256:d91ebeac603812a09cf6a886ba6e464f3bbb367411904ae3790dfe28311b15ad", + "sha256:d9a03ec6cb9f40a5c360f138b88266fd8f58408d71e89f536b4f91d85721d075", + "sha256:dadbcce51a10c07b7c72b0ce4a25e4b6dcb0c0372846afb8e5b6307a121eb99f", + "sha256:dba82204769d78c3fd31b35c3d5f46e06511936c5019c39f98320e05b08f794d", + "sha256:dbbf012be5f32533a490709ad597ad8a8ff80c582a95adc8d62af664e532f9ca", + "sha256:df01d6c4c81e15a7c88337b795bb7595a8596e92310266b5072c7e301168efbd", + "sha256:e0eb0a2dcc62478eb5b4cbb80b97bdee852d7e280b90e81f11b407d0b81c4287", + "sha256:e24045453384e0ae2a587d562df2a04d852672eb63051d16096d3f08aa4c7c2f", + "sha256:e44a86a47bbdf83b0a3ea4d7df5410d6b1a0de984fbd805fa5101f3624b9abe0", + "sha256:e4dc07e95495923d6fd4d6c27bf70769425b71c89053083843fd78f378558996", + "sha256:e89641f5175d65e2dbb44db15fe4ea48fade5d5bbb9868fdc2b4fce22f4a469d", + "sha256:e9570ad567f880ef675673992222746a124b9595506826b210fbe0ce3f0499cd", + "sha256:eb53f1e8adeeb2e78962bade0c08bfdc461853c7969706ed901821e009b35e31", + "sha256:eb92e47c92fcbcdc692f428da67db33337fa213756f7adb6a011f7b5a7a20740", + "sha256:ef55537ff511b5e0a43edb4c50a7bf7ba1c3eea20b4f49b1490f1e8e0e42c591", + "sha256:f39ae2f63f37472c17b4990f794035c9890418b1b8cca75c01193f3c8d3e01be", + "sha256:f413ce6e07e0d0dc9c433228727b619871532674b45165abafe201f200cc215f", + "sha256:f91f927a3215b8907e214af77200250bb6aae36eca3f760f89780d13e495388d", + "sha256:f9ea02ef40bb83823b2b04964459d281688fe173e20643870bb5d2edf68bc836", + "sha256:fcc0a4aa589de34bc56e1a80a740ee0f8c47611bdfb28cd1849de60660f3799d", + "sha256:fcc15fc462707b0680cff6242c48625da7f9a16a28a41bb8fd7a4280920e676c" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==7.11.0" + }, "exceptiongroup": { "hashes": [ "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", @@ -65,6 +167,15 @@ "markers": "python_version >= '3.9'", "version": "==8.4.2" }, + "pytest-cov": { + "hashes": [ + "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", + "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==7.0.0" + }, "tomli": { "hashes": [ "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", diff --git a/tests/test_compatibility_score.py b/tests/test_compatibility_score.py index 06dc265..f6d5a30 100644 --- a/tests/test_compatibility_score.py +++ b/tests/test_compatibility_score.py @@ -1,5 +1,5 @@ import pytest -from fortuneluckpredictor import compatibility_score +from src.fortuneluckpredictor import compatibility_score # Sample names for testing @pytest.fixture diff --git a/tests/test_lucky_number.py b/tests/test_lucky_number.py index d7f822a..62ad7ab 100644 --- a/tests/test_lucky_number.py +++ b/tests/test_lucky_number.py @@ -1,6 +1,6 @@ import pytest import math -from fortuneluckpredictor import get_lucky_number +from src.fortuneluckpredictor import luckyNumber @pytest.fixture def sample_ranges(): @@ -18,7 +18,7 @@ def test_sanity_check(): def test_output_type_and_bounds(sample_ranges): """Check that output is an integer within the expected bounds.""" for r in sample_ranges: - result = get_lucky_number.get_lucky_number(r) + result = luckyNumber.get_lucky_number(r) assert isinstance(result, int) a, b = r lo, hi = (a, b) if a <= b else (b, a) @@ -32,9 +32,9 @@ class FixedTime(datetime): @classmethod def now(cls, tz=None): return datetime(2025, 11, 3, 14, 45) - monkeypatch.setattr(get_lucky_number, "datetime", FixedTime) - first = get_lucky_number.get_lucky_number((1, 100)) - second = get_lucky_number.get_lucky_number((1, 100)) + monkeypatch.setattr(luckyNumber, "datetime", FixedTime) + first = luckyNumber.get_lucky_number((1, 100)) + second = luckyNumber.get_lucky_number((1, 100)) assert first == second # Returns different numbers at different times @@ -51,16 +51,16 @@ def now(cls, tz=None): else: cls._toggle = True return datetime(2025, 11, 2, 14, 45) - monkeypatch.setattr(get_lucky_number, "datetime", TimeVariant) - n1 = get_lucky_number.get_lucky_number((1, 100)) - n2 = get_lucky_number.get_lucky_number((1, 100)) + monkeypatch.setattr(luckyNumber, "datetime", TimeVariant) + n1 = luckyNumber.get_lucky_number((1, 100)) + n2 = luckyNumber.get_lucky_number((1, 100)) assert n1 != n2, f"Expected different results across distinct datetimes ({n1} == {n2})" def test_single_value_range(): """If range has only one number, that number must be returned.""" - assert get_lucky_number.get_lucky_number((42, 42)) == 42 + assert luckyNumber.get_lucky_number((42, 42)) == 42 def test_reversed_range_handled(): """Swapped a,b should still produce valid result.""" - val = get_lucky_number.get_lucky_number((100, 1)) + val = luckyNumber.get_lucky_number((100, 1)) assert 1 <= val <= 100 \ No newline at end of file From 2dead50958e4e1b127749d917e3bd346089b9fae Mon Sep 17 00:00:00 2001 From: Deng-Hanjun Date: Tue, 4 Nov 2025 17:51:58 -0500 Subject: [PATCH 19/20] update predict_day and add test_predict_day --- src/fortuneluckpredictor/predictDay.py | 13 +--- tests/test_predict_day.py | 94 ++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 tests/test_predict_day.py diff --git a/src/fortuneluckpredictor/predictDay.py b/src/fortuneluckpredictor/predictDay.py index 8372172..a4f93c3 100644 --- a/src/fortuneluckpredictor/predictDay.py +++ b/src/fortuneluckpredictor/predictDay.py @@ -25,17 +25,6 @@ } def predict_day(day: str | None = None) -> str: - """ - Predicts a fortune and daily message for a given day. - If no day is provided, uses the current weekday. - - Args: - day (str | None): The name or abbreviation of a day (e.g., "Mon", "Monday"). - If None, uses today's weekday. - - Returns: - str: A formatted string with the day's message and a fortune. - """ # If no day provided, use today's day name if not day: day = datetime.now().strftime("%A") @@ -55,4 +44,4 @@ def predict_day(day: str | None = None) -> str: fortune_text = rng.choice(fortunes) # Format nicely - return f"{day.capitalize()}: {message} Fortune: {fortune_text}" \ No newline at end of file + return f"{key.capitalize()}: {message} Fortune: {fortune_text}" \ No newline at end of file diff --git a/tests/test_predict_day.py b/tests/test_predict_day.py new file mode 100644 index 0000000..24089c5 --- /dev/null +++ b/tests/test_predict_day.py @@ -0,0 +1,94 @@ +import pytest +from fortuneluckpredictor.predictDay import predict_day + + +# --- Helpers --- + +def freeze_day(monkeypatch, year=2025, month=11, day=4): + #Freeze datetime.now() to a fixed date for deterministic tests. + from datetime import datetime as _DT + + class FixedDate(_DT): + @classmethod + def now(cls): + return cls(year, month, day) + + monkeypatch.setattr("fortuneluckpredictor.predictDay.datetime", FixedDate, raising=True) + + +def pin_fortunes(monkeypatch, items): + #Replace fortunes list inside predictDay. + monkeypatch.setattr("fortuneluckpredictor.predictDay.fortunes", items, raising=True) + + +# --- Tests --- + +def test_alias_normalization_is_case_and_space_insensitive(monkeypatch): + freeze_day(monkeypatch) + pin_fortunes(monkeypatch, ["ONLY_ONE"]) + for inp in ["fri", "Fri", " FRI "]: + out = predict_day(inp) + assert out.startswith("Friday:") + assert "Fortune: ONLY_ONE" in out + + +def test_full_day_name(monkeypatch): + freeze_day(monkeypatch) + pin_fortunes(monkeypatch, ["X"]) + out = predict_day("Monday") + assert out.startswith("Monday:") + assert "Fresh energy fills your week" in out + assert out.endswith("Fortune: X") + + +def test_blank_input_means_today(monkeypatch): + freeze_day(monkeypatch, 2025, 11, 5) # Wednesday + pin_fortunes(monkeypatch, ["ONLY_ONE"]) + out = predict_day("") # blank โ†’ today + assert out.startswith("Wednesday:") + assert "Fortune: ONLY_ONE" in out + + +def test_whitespace_input(monkeypatch): + freeze_day(monkeypatch, 2025, 11, 6) # Thursday + pin_fortunes(monkeypatch, ["Y"]) + out = predict_day(" ") + assert out.startswith("Thursday:") + assert out.endswith("Fortune: Y") + + +def test_invalid_day_raises(monkeypatch): + freeze_day(monkeypatch) + with pytest.raises(ValueError): + predict_day("Funday") + + +def test_same_input_same_output_within_run(monkeypatch): + freeze_day(monkeypatch) + pin_fortunes(monkeypatch, ["A", "B", "C", "D", "E", "F", "G", "H"]) + a = predict_day("Tuesday") + b = predict_day("Tuesday") + assert a == b, "Same (date, day) should yield same fortune" + +def test_different_day_different_output(monkeypatch): + freeze_day(monkeypatch) + pin_fortunes(monkeypatch, ["A", "B", "C", "D", "E", "F", "G", "H"]) + + monday_output = predict_day("Monday") + tuesday_output = predict_day("Tuesday") + + # Since RNG seed depends on day name, outputs should differ + assert monday_output != tuesday_output, "Different days should yield different fortunes" + +@pytest.mark.parametrize("alias, full", [ + ("mon", "Monday"), ("tue", "Tuesday"), ("tues", "Tuesday"), + ("wed", "Wednesday"), ("thu", "Thursday"), ("thur", "Thursday"), + ("thurs", "Thursday"), ("fri", "Friday"), ("sat", "Saturday"), + ("sun", "Sunday"), +]) +def test_alias_table(alias, full, monkeypatch): + freeze_day(monkeypatch) + pin_fortunes(monkeypatch, ["ONLY_ONE"]) + out = predict_day(alias) + assert out.startswith(f"{full}:") + assert "Fortune: ONLY_ONE" in out From cc7b4011a585bf7c19d1a0f6f098798c41b096d6 Mon Sep 17 00:00:00 2001 From: zz4206 Date: Tue, 4 Nov 2025 20:22:16 -0500 Subject: [PATCH 20/20] fix predictDay and predictDay tests --- src/fortuneluckpredictor/predictDay.py | 4 ++-- tests/test_lucky_number.py | 2 +- tests/test_predict_day.py | 26 +++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/fortuneluckpredictor/predictDay.py b/src/fortuneluckpredictor/predictDay.py index a4f93c3..432aee3 100644 --- a/src/fortuneluckpredictor/predictDay.py +++ b/src/fortuneluckpredictor/predictDay.py @@ -26,10 +26,10 @@ def predict_day(day: str | None = None) -> str: # If no day provided, use today's day name - if not day: + if not day or not day.strip(): day = datetime.now().strftime("%A") - d = day.strip().lower() + # Normalize to full day name key = d if d in DAY_MESSAGES else DAY_ALIASES.get(d) if not key: diff --git a/tests/test_lucky_number.py b/tests/test_lucky_number.py index 62ad7ab..355c0dc 100644 --- a/tests/test_lucky_number.py +++ b/tests/test_lucky_number.py @@ -63,4 +63,4 @@ def test_single_value_range(): def test_reversed_range_handled(): """Swapped a,b should still produce valid result.""" val = luckyNumber.get_lucky_number((100, 1)) - assert 1 <= val <= 100 \ No newline at end of file + assert 1 <= val <= 100 diff --git a/tests/test_predict_day.py b/tests/test_predict_day.py index 24089c5..aafec2c 100644 --- a/tests/test_predict_day.py +++ b/tests/test_predict_day.py @@ -1,5 +1,5 @@ import pytest -from fortuneluckpredictor.predictDay import predict_day +from src.fortuneluckpredictor import predictDay # --- Helpers --- @@ -13,12 +13,12 @@ class FixedDate(_DT): def now(cls): return cls(year, month, day) - monkeypatch.setattr("fortuneluckpredictor.predictDay.datetime", FixedDate, raising=True) + monkeypatch.setattr(predictDay,"datetime", FixedDate, raising=True) def pin_fortunes(monkeypatch, items): #Replace fortunes list inside predictDay. - monkeypatch.setattr("fortuneluckpredictor.predictDay.fortunes", items, raising=True) + monkeypatch.setattr(predictDay,"fortunes", items, raising=True) # --- Tests --- @@ -27,7 +27,7 @@ def test_alias_normalization_is_case_and_space_insensitive(monkeypatch): freeze_day(monkeypatch) pin_fortunes(monkeypatch, ["ONLY_ONE"]) for inp in ["fri", "Fri", " FRI "]: - out = predict_day(inp) + out = predictDay.predict_day(inp) assert out.startswith("Friday:") assert "Fortune: ONLY_ONE" in out @@ -35,7 +35,7 @@ def test_alias_normalization_is_case_and_space_insensitive(monkeypatch): def test_full_day_name(monkeypatch): freeze_day(monkeypatch) pin_fortunes(monkeypatch, ["X"]) - out = predict_day("Monday") + out = predictDay.predict_day("Monday") assert out.startswith("Monday:") assert "Fresh energy fills your week" in out assert out.endswith("Fortune: X") @@ -44,7 +44,7 @@ def test_full_day_name(monkeypatch): def test_blank_input_means_today(monkeypatch): freeze_day(monkeypatch, 2025, 11, 5) # Wednesday pin_fortunes(monkeypatch, ["ONLY_ONE"]) - out = predict_day("") # blank โ†’ today + out = predictDay.predict_day("") # blank โ†’ today assert out.startswith("Wednesday:") assert "Fortune: ONLY_ONE" in out @@ -52,7 +52,7 @@ def test_blank_input_means_today(monkeypatch): def test_whitespace_input(monkeypatch): freeze_day(monkeypatch, 2025, 11, 6) # Thursday pin_fortunes(monkeypatch, ["Y"]) - out = predict_day(" ") + out = predictDay.predict_day(" ") assert out.startswith("Thursday:") assert out.endswith("Fortune: Y") @@ -60,22 +60,22 @@ def test_whitespace_input(monkeypatch): def test_invalid_day_raises(monkeypatch): freeze_day(monkeypatch) with pytest.raises(ValueError): - predict_day("Funday") + predictDay.predict_day("Funday") def test_same_input_same_output_within_run(monkeypatch): freeze_day(monkeypatch) pin_fortunes(monkeypatch, ["A", "B", "C", "D", "E", "F", "G", "H"]) - a = predict_day("Tuesday") - b = predict_day("Tuesday") + a = predictDay.predict_day("Tuesday") + b = predictDay.predict_day("Tuesday") assert a == b, "Same (date, day) should yield same fortune" def test_different_day_different_output(monkeypatch): freeze_day(monkeypatch) pin_fortunes(monkeypatch, ["A", "B", "C", "D", "E", "F", "G", "H"]) - monday_output = predict_day("Monday") - tuesday_output = predict_day("Tuesday") + monday_output = predictDay.predict_day("Monday") + tuesday_output = predictDay.predict_day("Tuesday") # Since RNG seed depends on day name, outputs should differ assert monday_output != tuesday_output, "Different days should yield different fortunes" @@ -89,6 +89,6 @@ def test_different_day_different_output(monkeypatch): def test_alias_table(alias, full, monkeypatch): freeze_day(monkeypatch) pin_fortunes(monkeypatch, ["ONLY_ONE"]) - out = predict_day(alias) + out = predictDay.predict_day(alias) assert out.startswith(f"{full}:") assert "Fortune: ONLY_ONE" in out