From 7ba340a33a90f342df5f636c43593692d9d9197b Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Wed, 14 Oct 2026 21:21:44 +0800 Subject: [PATCH] feat: add package skeleton, constants.py and smoke tests Task: MIL-001#3 Task: MIL-001#7 --- src/password_manager/__init__.py | 7 ++++ src/password_manager/constants.py | 56 +++++++++++++++++++++++++++++++ tests/unit/test_constants.py | 18 ++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/password_manager/__init__.py create mode 100644 src/password_manager/constants.py create mode 100644 tests/unit/test_constants.py diff --git a/src/password_manager/__init__.py b/src/password_manager/__init__.py new file mode 100644 index 0000000..2343237 --- /dev/null +++ b/src/password_manager/__init__.py @@ -0,0 +1,7 @@ +"""@brief A Tkinter password manager that stores entries in a JSON file. + +@file __init__.py +@package password_manager +""" + +__version__ = "0.1.0" diff --git a/src/password_manager/constants.py b/src/password_manager/constants.py new file mode 100644 index 0000000..10e400b --- /dev/null +++ b/src/password_manager/constants.py @@ -0,0 +1,56 @@ +"""@brief Constants of the password manager. + +@file constants.py +@details Every literal that more than one module needs, or that a reader may +want to change, lives here and nowhere else. +""" + +import string +from pathlib import Path + +# Storage +DATA_FILE_NAME = "data.json" ##< Name of the JSON file that holds the entries. +DATA_FILE_PATH = Path( + DATA_FILE_NAME +) ##< Default location, relative to the working directory. +JSON_INDENT = 4 ##< Indentation of the written JSON, for readability. +KEY_EMAIL = "email" ##< JSON key of an entry's e-mail address. +KEY_PASSWORD = "password" ##< JSON key of an entry's password. + +# Password generator +LETTERS = string.ascii_letters ##< Letters a password may use. +DIGITS = string.digits ##< Digits a password may use. +SYMBOLS = "!#$%&()*+" ##< Symbols a password may use. +MIN_LETTERS = 8 ##< Fewest letters in a generated password. +MAX_LETTERS = 10 ##< Most letters in a generated password. +MIN_SYMBOLS = 2 ##< Fewest symbols in a generated password. +MAX_SYMBOLS = 4 ##< Most symbols in a generated password. +MIN_DIGITS = 2 ##< Fewest digits in a generated password. +MAX_DIGITS = 4 ##< Most digits in a generated password. + +# Window +WINDOW_TITLE = "Password Manager" ##< Title of the main window. +WINDOW_PADDING = 50 ##< Padding around the window content, in pixels. +LOGO_SIZE = 200 ##< Width and height of the logo canvas, in pixels. +DEFAULT_EMAIL = "name@example.com" ##< E-mail address the form starts with. +ENTRY_WIDTH_WIDE = 35 ##< Width in characters of the e-mail and add fields. +ENTRY_WIDTH_NARROW = 21 ##< Width in characters of the website and password fields. + +# Labels and messages +LABEL_WEBSITE = "Website:" +LABEL_EMAIL = "Email/Username:" +LABEL_PASSWORD = "Password:" +BUTTON_SEARCH = "Search" +BUTTON_GENERATE = "Generate Password" +BUTTON_ADD = "Add" +TITLE_OOPS = "Oops" +TITLE_SAVED = "Saved" +TITLE_FOUND = "Found" +MESSAGE_EMPTY_FIELDS = "Please don't leave any fields empty!" +MESSAGE_NO_DATA_FILE = "No Data File Found." +MESSAGE_NO_DETAILS = "No details for {website} exists." +MESSAGE_CONFIRM_SAVE = ( + "These are the details entered:\nEmail: {email}\n" + "Password: {password}\nIs it ok to save?" +) +MESSAGE_DETAILS = "Email: {email}\nPassword: {password}" diff --git a/tests/unit/test_constants.py b/tests/unit/test_constants.py new file mode 100644 index 0000000..ee39465 --- /dev/null +++ b/tests/unit/test_constants.py @@ -0,0 +1,18 @@ +"""Smoke test: the package and its constants import and hold sane values.""" + +import password_manager +from password_manager import constants + + +def test_package_has_version() -> None: + assert password_manager.__version__ + + +def test_data_file_name_is_json() -> None: + assert constants.DATA_FILE_NAME.endswith(".json") + + +def test_password_length_bounds_are_ordered() -> None: + assert constants.MIN_LETTERS <= constants.MAX_LETTERS + assert constants.MIN_SYMBOLS <= constants.MAX_SYMBOLS + assert constants.MIN_DIGITS <= constants.MAX_DIGITS