diff --git a/.DS_Store b/.DS_Store index 54468648c..a86d98c0f 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 1d75c3418..130fc190f 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -1,12 +1,27 @@ -name: Lint +name: Format code -on: [push, pull_request] +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] jobs: - lint: + format: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - uses: psf/black@stable with: - options: "--check --verbose" + options: "--verbose" src: "./src" + - name: Sort imports with isort + run: | + pip install isort + isort . + - name: Remove unused imports with autoflake + run: | + pip install autoflake + autoflake --in-place --remove-all-unused-imports --remove-unused-variables --recursive . diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2f554f4b3..3ea009484 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,9 +6,9 @@ name: CI on: # Triggers the workflow on push or pull request events but only for the main branch push: - branches: [ pratik_testing ] + branches: [ main ] pull_request: - branches: [ pratik_testing ] + branches: [ main ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: @@ -53,13 +53,19 @@ jobs: - name: Install pylint run: | pip install pylint + - name: Run pylint + run: | + pylint -r y src/ - name: Run tests env: API_TOKEN: ${{ secrets.API_TOKEN }} CHAT_ID: ${{ secrets.CHAT_ID }} + DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} + CHANNEL_ID: ${{secrets.CHANNEL_ID }} run: | export PYTHONPATH=src python -m pytest -v --cov=src/ --cov-report=xml - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 - + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index d7a74e544..735e43f86 100644 --- a/.gitignore +++ b/.gitignore @@ -128,4 +128,7 @@ dmypy.json # Pyre type checker .pyre/ -temp.txt \ No newline at end of file +temp.txt + +# pickle files +.pickle \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1e948f2aa..41dd9ebee 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -59,8 +59,7 @@ representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -rsinha3@ncsu.edu. +reported to the community leaders responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e3a2a0c09..5fd6f9e99 100755 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,101 +1,94 @@ -# Contributing to SlashBot +# Contributing to FinBot -Follow the set of guidelines below to contribute to SlashBot! +Thank you for your interest in contributing to our project. Please make sure to read and follow these guidelines for a smooth and effective contribution process. ## Code of Conduct -By participating, you are expected to uphold this code. Please report unacceptable behavior to psomash@ncsu.edu or secheaper@gamil.com. +Everyone participating in this project needs to abide by the aPAS - A Personal Agile Scheduler Code of Conduct that can be found under the main repository link as a [CODE_OF_CONDUCT.md](https://github.com/vyshnavi-adusumelli/FinBot/blob/main/CODE_OF_CONDUCT.md) file. By participating, you are expected to uphold this code. Please report unacceptable behavior to any of the original team members listed at the bottom of [README.md](https://github.com/vyshnavi-adusumelli/FinBot/blob/main/README.md). -Prerequistes required before starting this project - -1. Must be a graduate student at NC State University -2. Must be a student in Software Engineering Course in Fall 2021 -3. Have proficiency in Python - -## How can I Contribute - +## How can You Contribute ### Reporting Bugs -This section guides you through submitting a bug report for SlashBot. -Following these guidelines helps maintainers and the community understand your report, reproduce the behavior and find related reports. +This section guides you through submitting a bug report for FinBot. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior and find related reports. -Before Submitting A Bug Report +### Before Submitting A Bug Report -Check the debugging guide +- Check the debugging guide. -Check the FAQs on the forum for a list of common questions and problems. -Determine which repository the problem should be reported in. +- Review the FAQs on the forum for common questions and problems. -Perform a cursory search to see if the problem has already been reported. +- Perform a cursory search to see if the problem has already been reported. -## How Do I Submit A (Good) Bug Report? +- When you are creating a bug report, please ensure that you include as many details as possible to understand the issue. -Use a clear and descriptive title for the issue to identify the problem. +### How Do I Submit A (Good) Bug Report? -Describe the exact steps which reproduce the problem in as many details as possible. +- Use a clear and descriptive title for the issue to identify the problem. -Provide specific examples to demonstrate the steps. +- Describe the exact steps which reproduce the problem in as many details as possible. -Describe the behavior you observed after following the steps and point out what exactly is the problem with that behavior. +- Provide specific examples to demonstrate the steps. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use Markdown code blocks. -Explain which behavior you expected to see instead and why. +- If the problem is related to performance or memory, then ensure that you include a CPU profile capture with your report. -Include screenshots and animated GIFs which show you following the described steps and clearly demonstrate the problem. +- Include screenshots and animated GIFs which show you following the described steps and clearly demonstrate the problem. -If the problem is related to performance or memory, include a CPU profile capture with your report. +- If the problem wasn't triggered by a specific action, describe what you were doing before the problem happened and share more information using the guidelines below. -## Pull Requests +### Suggesting Enhancements -The process described here has several goals: +This section guides you through submitting a suggestion for FinBot, including completely new features and minor improvements to existing functionality. -Maintain the projects quality +Enhancement suggestions are tracked as GitHub issues. After you've determine your enhancement suggestion, create an issue on that repository and provide with information like title, step-by-step description, specific examples. Giving more detailed information will help us understand the suggestion better. -Fix problems that are important to users +Provide details like +- What is the enhancement? +- Suggestions to implement the enhancement -Enable a sustainable system for the projects maintainers to review contributions +We welcome suggestions to improve the bot; please add them to the TO-DO list. -## Tips to Extend +### Pull Requests -Check the Projects tab for TO-DO list and pick the feature you find interesting to work on. +Contributing through pull requests is essential for maintaining project quality. Here's how you can create a pull request: -Create a branch and implement the feature in Python using Telegram bot and test it locally. +- Check the Projects tab for the TO-DO list and pick/create a feature to work on. -Write corresponding test cases to ensure it is not breaking the existing system. +- Create a branch and implement the feature in Python, and test it locally. -Create pull request and request for the code review. Once the request is approved, merge to main. +- Write corresponding test cases to ensure it doesn't break the existing system. + +- Create a pull request and request a code review. Once approved, merge it into the main branch. -Any suggestions to improve the bot is appreciated. Please add it to the TO-DO list. +Key features to pay attention to -## More tips for developers -### Heroku deployment -The bot is deployed on [Heroku](https://www.heroku.com/), a website used to host source code and apps. +- Maintain the projects quality -Quoted directly from their page: +- Fix problems that are important to users + +- Enable a sustainable system for the projects maintainers to review contributions + +- Add a description of the modification. Add images for the modification if possible. + +- Insert a clear and descriptive title. -"Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud." +## Style Guides +### Git Commit Messages -#### Why this is useful +- Describe why any particular modification is being made. -Before, users had to download source code, insert their API key from telegram, and then run the python file. -This can lead to both user error and error within the source code. By deploying it on heroku, you ensure that -the code is available anywhere, at anytime, without having to download files. +- Give a detailed description about the limitations of current code. +- Use the imperative mood ("Move cursor to..." not "Moves cursor to...") -#### How we created the bot +- Limit the first line to 72 characters or less -1. A heroku account was created with the shared mydollarbot@gmail.com credentials -2. A new app was created called my_dollar_bot. -3. Within github, we added a [new action](.github/workflows/deploy.yml) to deploy to the heroku bot -4. For every push, the source code is deployed to heroku, and python code/bot.py is executed, starting the bot +- Link an issue to the change -This way, if users want to use the bot without developing, they can simply use this bot instead of having to run the -application locally. +### Python Style Guides -#### How to develop the heroku bot server +All Python code is linted with Pylint. Ensure that before you commit any changes, your code passes all the default pylint checks and pipeline checks. Pylint can be installed with pip install pylint. -- Follow steps 1-3 above, except replace with your own email. Install Heroku cli [here](https://devcenter.heroku.com/articles/heroku-cli#download-and-install). -- Within github, add a secret for the heroku api key. -- Create a new CI/CD pipeline (refer our yaml file [here](.github/workflows/deploy.yml)) and set up github actions. -- Create a new Procfile and add `worker: python code/bot.py`. Refer ours [here](https://github.com/mtkumar123/MyDollarBot/blob/main/Procfile) -- Within your heroku dashboard, you can view logs for the bot to understand well the deployment is running. You can also run the command `heroku logs` or `heroku logs -t` +## Need Additional Help? +Due to any reason, if you feel like you have reservations related to the process, feel free to reach us out at [vadusum@ncsu.edu] Github process can be a bit complex and we don't want to lose your valuable contributions because of that reason. We are extremely glad that you have visited us and will make our project much better. diff --git a/README.md b/README.md index 5ad8d3a88..f7efea138 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,73 @@ -# :money_with_wings: SlashBot -












Shubham Mankar |
- Pratik Devnani |
- Moksh Jain |
- Rahil Sarvaiya |
- Anushi Keswani |
+ Harshavardhan Bandaru |
+ Vyshnavi Adusumeli |
+ Tejaswini Panati |
+




"+ tabulate(table, headers='firstrow')+"" bot.send_message(chat_id, spend_total_str, parse_mode="HTML") @@ -366,10 +307,8 @@ def download_history(message): chat_id = str(message.chat.id) count = 0 table = [["Category", "Date", "Amount in $"]] - if chat_id not in list(user_list.keys()): - raise Exception("Sorry! No spending records found!") - if len(user_list[chat_id].transactions) == 0: - raise Exception("Sorry! No spending records found!") + if chat_id not in list(user_list.keys()): raise Exception("Sorry! No spending records found!") + if len(user_list[chat_id].transactions) == 0: raise Exception("Sorry! No spending records found!") else: for category in user_list[chat_id].transactions.keys(): for transaction in user_list[chat_id].transactions[category]: @@ -377,8 +316,7 @@ def download_history(message): date = transaction["Date"].strftime("%m/%d/%y") value = format(transaction["Value"], ".2f") table.append([date, category, "$"+value]) - if count == 0: - raise Exception("Sorry! No spending records found!") + if count == 0: raise Exception("Sorry! No spending records found!") s = io.StringIO() csv.writer(s).writerows(table) @@ -407,10 +345,8 @@ def send_email(message): chat_id = str(message.chat.id) count = 0 table = [["Category", "Date", "Amount in $"]] - if chat_id not in list(user_list.keys()): - raise Exception("Sorry! No spending records found!") - if len(user_list[chat_id].transactions) == 0: - raise Exception("Sorry! No spending records found!") + if chat_id not in list(user_list.keys()): raise Exception("Sorry! No spending records found!") + if len(user_list[chat_id].transactions) == 0: raise Exception("Sorry! No spending records found!") else: for category in user_list[chat_id].transactions.keys(): for transaction in user_list[chat_id].transactions[category]: @@ -418,8 +354,7 @@ def send_email(message): date = transaction["Date"].strftime("%m/%d/%y") value = format(transaction["Value"], ".2f") table.append([date, category, "$"+value]) - if count == 0: - raise Exception("Sorry! No spending records found!") + if count == 0: raise Exception("Sorry! No spending records found!") s = io.StringIO() csv.writer(s).writerows(table) @@ -446,10 +381,8 @@ def acceptEmailId(message): chat_id = str(message.chat.id) count = 0 table = [["Category", "Date", "Amount in $"]] - if chat_id not in list(user_list.keys()): - raise Exception("Sorry! No spending records found!") - if len(user_list[chat_id].transactions) == 0: - raise Exception("Sorry! No spending records found!") + if chat_id not in list(user_list.keys()): raise Exception("Sorry! No spending records found!") + if len(user_list[chat_id].transactions) == 0: raise Exception("Sorry! No spending records found!") else: for category in user_list[chat_id].transactions.keys(): for transaction in user_list[chat_id].transactions[category]: @@ -457,10 +390,9 @@ def acceptEmailId(message): date = transaction["Date"].strftime("%m/%d/%y") value = format(transaction["Value"], ".2f") table.append([date, category, "$"+value]) - if count == 0: - raise Exception("Sorry! No spending records found!") + if count == 0: raise Exception("Sorry! No spending records found!") - with open('history.csv', 'w', newline = '') as file: + with open('history.csv', 'w', newline = '', encoding='utf-8') as file: writer = csv.writer(file) writer.writerows(table) # s = io.StringIO() @@ -474,10 +406,7 @@ def acceptEmailId(message): # writer.writerow(u"date", u"category", u"cost") # bot.send_document(chat_id, buf) - mail_content = '''Hello, - This email has an attached copy of your expenditure history. - Thank you! - ''' + mail_content = '''Hello, This email has an attached copy of your expenditure history. Thank you!''' #The mail addresses and password sender_address = 'secheaper@gmail.com' sender_pass = 'csc510se' @@ -512,8 +441,7 @@ def acceptEmailId(message): except Exception as ex: logger.error(str(ex), exc_info=True) bot.reply_to(message, str(ex)) - else: - bot.send_message(message.chat.id, 'incorrect email') + else: bot.send_message(message.chat.id, 'incorrect email') @@ -529,25 +457,16 @@ def command_display(message): :return: None """ chat_id = str(message.chat.id) - if chat_id not in user_list or user_list[chat_id].get_number_of_transactions() == 0: - bot.send_message( - chat_id, "Oops! Looks like you do not have any spending records!" - ) + if chat_id not in user_list or user_list[chat_id].get_number_of_transactions() == 0: bot.send_message(chat_id, "Oops! Looks like you do not have any spending records!") else: try: markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 - for mode in user_list[chat_id].spend_display_option: - markup.add(mode) - msg = bot.reply_to( - message, - "Please select a category to see the total expense", - reply_markup=markup, - ) + for mode in user_list[chat_id].spend_display_option: markup.add(mode) + msg = bot.reply_to(message, "Please select a category to see the total expense", reply_markup=markup,) bot.register_next_step_handler(msg, display_total) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Oops! - \nError : " + str(ex)) @@ -565,13 +484,9 @@ def display_total(message): chat_id = str(message.chat.id) day_week_month = message.text - if day_week_month not in user_list[chat_id].spend_display_option: - raise Exception( - 'Sorry I can\'t show spendings for "{}"!'.format(day_week_month) - ) + if day_week_month not in user_list[chat_id].spend_display_option: raise Exception('Sorry I can\'t show spendings for "{}"!'.format(day_week_month)) - if len(user_list[chat_id].transactions) == 0: - raise Exception("Oops! Looks like you do not have any spending records!") + if len(user_list[chat_id].transactions) == 0: raise Exception("Oops! Looks like you do not have any spending records!") bot.send_message(chat_id, "Hold on! Calculating...") @@ -582,15 +497,9 @@ def display_total(message): for category in user_list[chat_id].transactions.keys(): for transaction in user_list[chat_id].transactions[category]: if transaction["Date"].strftime("%d") == query.strftime("%d"): - query_result += "Category {} Date {} Value {:.2f} \n".format( - category, - transaction["Date"].strftime(dateFormat), - transaction["Value"], - ) + query_result += "Category {} Date {} Value {:.2f} \n".format(category,transaction["Date"].strftime(dateFormat),transaction["Value"]) total_value += transaction["Value"] - total_spendings = "Here are your total spendings for the date {} \n".format( - datetime.today().strftime("%m/%d/%Y") - ) + total_spendings = "Here are your total spendings for the date {} \n".format(datetime.today().strftime("%m/%d/%Y")) total_spendings += query_result total_spendings += "Total Value {:.2f}".format(total_value) bot.send_message(chat_id, total_spendings) @@ -603,23 +512,14 @@ def display_total(message): for category in user_list[chat_id].transactions.keys(): for transaction in user_list[chat_id].transactions[category]: if transaction["Date"].strftime("%m") == query.strftime("%m"): - query_result += "Category {} Date {} Value {:.2f} \n".format( - category, - transaction["Date"].strftime(dateFormat), - transaction["Value"], - ) + query_result += "Category {} Date {} Value {:.2f} \n".format(category,transaction["Date"].strftime(dateFormat),transaction["Value"]) total_value += transaction["Value"] - total_spendings = ( - "Here are your total spendings for the Month {} \n".format( - datetime.today().strftime("%B") - ) - ) + total_spendings = ("Here are your total spendings for the Month {} \n".format(datetime.today().strftime("%B"))) total_spendings += query_result total_spendings += "Total Value {:.2f}\n".format(total_value) total_spendings += "Budget for the month {}".format(str(budget_value)) bot.send_message(chat_id, total_spendings) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, str(ex)) @@ -637,22 +537,13 @@ def edit1(message): try: if chat_id in list(user_list.keys()): - msg = bot.reply_to( - message, - "Please enter the date (in mm/dd/yyyy format), category and " - "value of the transaction you made (Eg: 01/03/2021,Transport,25)", - ) + msg = bot.reply_to(message,"Please enter the date (in mm/dd/yyyy format), category and value of the transaction you made (Eg: 01/03/2021,Transport,25)") bot.register_next_step_handler(msg, edit_list2) - else: - bot.send_message(chat_id, "No data found") + else:bot.send_message(chat_id, "No data found") except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) - bot.reply_to( - message, - "Processing Failed - \nError : Incorrect format - (Eg: 01/03/2021,Transport,25)", - ) + bot.reply_to(message,"Processing Failed - \nError : Incorrect format - (Eg: 01/03/2021,Transport,25)") def edit_list2(message): @@ -680,24 +571,17 @@ def edit_list2(message): markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 choices = ["Date", "Category", "Cost"] - for c in choices: - markup.add(c) + for c in choices: markup.add(c) for transaction in user_list[chat_id].transactions[info_category]: if transaction["Date"].date() == info_date: if transaction["Value"] == float(info_value): - user_list[chat_id].store_edit_transaction( - transaction, info_category - ) - choice = bot.reply_to( - message, "What do you want to update?", reply_markup=markup - ) + user_list[chat_id].store_edit_transaction( transaction, info_category) + choice = bot.reply_to(message, "What do you want to update?", reply_markup=markup) bot.register_next_step_handler(choice, edit3) break - else: - bot.reply_to(message, "Transaction not found") + else:bot.reply_to(message, "Transaction not found") except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Processing Failed - Error: " + str(ex)) @@ -715,18 +599,13 @@ def edit3(message): chat_id = str(message.chat.id) markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 - for category in user_list[chat_id].spend_categories: - markup.add(category) + for category in user_list[chat_id].spend_categories: markup.add(category) if choice1 == "Date": - new_date = bot.reply_to( - message, "Please enter the new date (in mm/dd/yyyy format)" - ) + new_date = bot.reply_to(message, "Please enter the new date (in mm/dd/yyyy format)") bot.register_next_step_handler(new_date, edit_date) if choice1 == "Category": - new_cat = bot.reply_to( - message, "Please select the new category", reply_markup=markup - ) + new_cat = bot.reply_to(message, "Please select the new category", reply_markup=markup) bot.register_next_step_handler(new_cat, edit_cat) if choice1 == "Cost": @@ -751,12 +630,7 @@ def edit_date(message): return updated_transaction = user_list[chat_id].edit_transaction_date(user_date) user_list[chat_id].save_user(chat_id) - edit_message = ( - "Date is updated. Here is the new transaction. \n Date {}. Value {}. \n".format( - updated_transaction["Date"].strftime("%m/%d/%Y %H:%M:%S"), - format(updated_transaction["Value"], ".2f"), - ) - ) + edit_message = ("Date is updated. Here is the new transaction. \n Date {}. Value {}. \n".format(updated_transaction["Date"].strftime("%m/%d/%Y %H:%M:%S"),format(updated_transaction["Value"], ".2f"))) bot.reply_to(message, edit_message) @@ -774,11 +648,9 @@ def edit_cat(message): updated_transaction = user_list[chat_id].edit_transaction_category(new_category) if updated_transaction: user_list[chat_id].save_user(chat_id) - edit_message = "Category has been edited." - bot.reply_to(message, edit_message) + bot.reply_to(message, "Category has been edited.") else: - edit_message = "Category has not been edited successfully" - bot.reply_to(message, edit_message) + bot.reply_to(message, "Category has not been edited successfully") def edit_cost(message): @@ -796,11 +668,7 @@ def edit_cost(message): if new_cost != 0: user_list[chat_id].save_user(chat_id) updated_transaction = user_list[chat_id].edit_transaction_value(new_cost) - edit_message = "Value is updated. Here is the new transaction. \n Date {}. Value {}. \n".format( - updated_transaction["Date"].strftime("%m/%d/%Y %H:%M:%S"), - format(updated_transaction["Value"], ".2f"), - ) - bot.reply_to(message, edit_message) + bot.reply_to(message, "Value is updated. Here is the new transaction. \n Date {}. Value {}. \n".format(updated_transaction["Date"].strftime("%m/%d/%Y %H:%M:%S"),format(updated_transaction["Value"], ".2f"))) else: bot.reply_to(message, "The cost is invalid") @@ -822,41 +690,23 @@ def handle_budget_document_csv(message): chat_id = str(message.chat.id) file_info = bot.get_file(message.document.file_id) download_file = bot.download_file(file_info.file_path) - with open("data/{}_spending.csv".format(chat_id), mode="wb") as f: - f.write(download_file) - unknown_spending = user_list[chat_id].read_budget_csv( - "data/{}_spending.csv".format(chat_id), chat_id - ) + with open("data/{}_spending.csv".format(chat_id), mode="wb") as f: f.write(download_file) + unknown_spending = user_list[chat_id].read_budget_csv("data/{}_spending.csv".format(chat_id), chat_id) for _, row in unknown_spending.iterrows(): text = "How do you want to categorize the following transaction \n" - text += "Date: {}. Description: {}. Debit: {}. \n".format( - row["date"], row["description"], row["debit"] - ) + text += "Date: {}. Description: {}. Debit: {}. \n".format(row["date"], row["description"], row["debit"]) buttons = telebot.types.InlineKeyboardMarkup(row_width=3) for category in user_list[chat_id].spend_categories: - callback = "{},{},{},{}".format( - category, row["date"], row["debit"], row["description"] - ) - buttons.add( - telebot.types.InlineKeyboardButton(category, callback_data=callback) - ) + callback = "{},{},{},{}".format(category, row["date"], row["debit"], row["description"]) + buttons.add(telebot.types.InlineKeyboardButton(category, callback_data=callback)) bot.send_message(chat_id, text, reply_markup=buttons) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Processing Failed - Error: " + str(ex)) -def is_csv_callback(query): - """ - Callback to identify if the button pressed was from the csv function - - :param query: the button pressed - :return: if the button pressed relates to the csv - """ - return "," in query.data - +def is_csv_callback(query): return "," in query.data @bot.callback_query_handler(func=is_csv_callback) def csv_callback(call): @@ -876,14 +726,9 @@ def csv_callback(call): debit = float(data[2]) description = data[3] chat_id = str(call.from_user.id) - user_list[chat_id].create_rules_and_add_unknown_spending( - category, description, date, debit, chat_id - ) - bot.delete_message( - chat_id=call.from_user.id, message_id=call.message.message_id - ) + user_list[chat_id].create_rules_and_add_unknown_spending(category, description, date, debit, chat_id) + bot.delete_message(chat_id=call.from_user.id, message_id=call.message.message_id) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.send_message(call.from_user.id, "Processing Failed - Error: " + str(ex)) @@ -902,13 +747,11 @@ def category_add(message): try: chat_id = str(message.chat.id) option.pop(chat_id, None) - if chat_id not in user_list.keys(): - user_list[chat_id] = User(chat_id) + if chat_id not in user_list.keys(): user_list[chat_id] = User(chat_id) category = bot.reply_to(message, "Enter category name") bot.register_next_step_handler(category, receive_new_category) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Oh no. " + str(ex)) @@ -924,16 +767,11 @@ def receive_new_category(message): try: category = message.text.strip() chat_id = str(message.chat.id) - if category == "": # category cannot be empty - raise Exception("Category name cannot be empty") - if category in user_list[chat_id].transactions: - raise Exception("Category already exists!") + if category == "": raise Exception("Category name cannot be empty") # category cannot be empty + if category in user_list[chat_id].transactions: raise Exception("Category already exists!") user_list[chat_id].add_category(category, chat_id) - bot.send_message( - chat_id, "{} has been added as a new category".format(category) - ) + bot.send_message(chat_id, "{} has been added as a new category".format(category)) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Oh no. " + str(ex)) @@ -950,14 +788,11 @@ def category_list(message): try: chat_id = str(message.chat.id) option.pop(chat_id, None) - if chat_id not in user_list.keys(): - user_list[chat_id] = User(chat_id) + if chat_id not in user_list.keys(): user_list[chat_id] = User(chat_id) chat_id = str(message.chat.id) - if len(user_list[chat_id].transactions.keys()) == 0: - raise Exception("Sorry! No categories found!") + if len(user_list[chat_id].transactions.keys()) == 0: raise Exception("Sorry! No categories found!") category_list_str = "Here is your category list : \n" - for index, category in enumerate(user_list[chat_id].transactions.keys()): - category_list_str += "{}. {}".format(index + 1, category + "\n") + for index, category in enumerate(user_list[chat_id].transactions.keys()): category_list_str += "{}. {}".format(index + 1, category + "\n") bot.send_message(chat_id, category_list_str) except Exception as ex: @@ -977,18 +812,15 @@ def category_delete(message): try: chat_id = str(message.chat.id) option.pop(chat_id, None) - if chat_id not in user_list.keys(): - user_list[chat_id] = User(chat_id) + if chat_id not in user_list.keys(): user_list[chat_id] = User(chat_id) spend_categories = user_list[chat_id].spend_categories markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 - for c in spend_categories: - markup.add(c) + for c in spend_categories: markup.add(c) msg = bot.reply_to(message, "Select Category", reply_markup=markup) bot.register_next_step_handler(msg, receive_delete_category) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Processing Failed - \nError : " + str(ex)) @@ -1004,16 +836,11 @@ def receive_delete_category(message): try: chat_id = str(message.chat.id) category = message.text.strip() - if category not in user_list[chat_id].transactions: - raise Exception("Oops! Category does not exist!") - if len(user_list[chat_id].transactions[category]) != 0: - raise Exception( - "Sorry! This category has transactions. Delete those transactions to proceed." - ) + if category not in user_list[chat_id].transactions: raise Exception("Oops! Category does not exist!") + if len(user_list[chat_id].transactions[category]) != 0: raise Exception("Sorry! This category has transactions. Delete those transactions to proceed.") user_list[chat_id].delete_category(category, chat_id) bot.reply_to(message, "{} has been removed from category list".format(category)) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, str(ex)) @@ -1033,10 +860,7 @@ def command_delete(message): monthFormat = "%m/%Y" chat_id = str(message.chat.id) try: - if ( - chat_id in user_list - and user_list[chat_id].get_number_of_transactions() != 0 - ): + if (chat_id in user_list and user_list[chat_id].get_number_of_transactions() != 0): curr_day = datetime.now() prompt = "Enter the day, month, or All\n" prompt += f"\n\tExample day: {curr_day.strftime(dateFormat)}\n" @@ -1044,14 +868,10 @@ def command_delete(message): reply_message = bot.reply_to(message, prompt) bot.register_next_step_handler(reply_message, process_delete_argument) else: - delete_history_text = ( - "No records to be deleted. Start adding your expenses to keep track of your " - "spendings! " - ) + delete_history_text = ("No records to be deleted. Start adding your expenses to keep track of your spendings! ") bot.send_message(chat_id, delete_history_text) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Processing Failed - \nError : " + str(ex)) @@ -1072,20 +892,16 @@ def process_delete_argument(message): date = None is_month = False - if text.lower() == "all": - date = "all" + if text.lower() == "all": date = "all" else: # try and parse as Date-Month-Year - if user_list[chat_id].validate_date_format(text, dateFormat) is not None: - date = user_list[chat_id].validate_date_format(text, dateFormat) + if user_list[chat_id].validate_date_format(text, dateFormat) is not None: date = user_list[chat_id].validate_date_format(text, dateFormat) # try and parse as Month-Year elif user_list[chat_id].validate_date_format(text, monthFormat) is not None: date = user_list[chat_id].validate_date_format(text, monthFormat) is_month = True - if date is None: - # if none of the formats worked - bot.reply_to(message, "Error parsing date") + if date is None: bot.reply_to(message, "Error parsing date") else: # get the records either by given day, month, or all records records_to_delete = user_list[chat_id].get_records_by_date(date, is_month) @@ -1119,8 +935,7 @@ def handle_confirmation(message, records_to_delete): user_list[chat_id].deleteHistory(records_to_delete) user_list[chat_id].save_user(chat_id) bot.send_message(message.chat.id, "Successfully deleted records") - else: - bot.send_message(message.chat.id, "No records deleted") + else: bot.send_message(message.chat.id, "No records deleted") def get_calendar_buttons(user): @@ -1144,28 +959,16 @@ def get_calendar_buttons(user): # for each day in the total days # for the first day, figure out how many ' ' to append row = [] - if m[0] != 6: - row = [ - types.InlineKeyboardButton(" ", callback_data="none") - for _ in range(m[0] + 1) - ] + if m[0] != 6: row = [types.InlineKeyboardButton(" ", callback_data="none") for _ in range(m[0] + 1)] for day in range(1, m[1] + 1): # if it is on a sunday, start a new row if user.curr_date.replace(day=day).weekday() == 6: kb.row(*row) row = [] - row.append( - types.InlineKeyboardButton( - day, - callback_data="{},{},{}".format( - user.curr_date.year, user.curr_date.month, day - ), - ) - ) + row.append(types.InlineKeyboardButton(day,callback_data="{},{},{}".format(user.curr_date.year, user.curr_date.month, day))) # finish out the last row if len(row) != 7: - for _ in range(7 - len(row)): - row.append(types.InlineKeyboardButton(" ", callback_data="none")) + for _ in range(7 - len(row)): row.append(types.InlineKeyboardButton(" ", callback_data="none")) kb.row(*row) return kb @@ -1192,8 +995,7 @@ def get_chart(message): chat_id = str(message.chat.id) chart_file = user_list[chat_id].create_chart(chat_id) for cf in chart_file: - with open(cf, "rb") as f: - bot.send_photo(chat_id, f) + with open(cf, "rb") as f: bot.send_photo(chat_id, f) # bot.send_photo(chat_id, cf) @@ -1206,26 +1008,12 @@ def create_header(user): :return: the header row """ # get the month name - row = [ - ( - types.InlineKeyboardButton( - user.curr_date.strftime("%B"), callback_data="none" - ) - ) - ] - if user.curr_date > user.min_date: - # if we should be able to go back a month - row.append(types.InlineKeyboardButton("<", callback_data="prev")) - else: - # append a blank - row.append(types.InlineKeyboardButton(" ", callback_data="none")) + row = [(types.InlineKeyboardButton(user.curr_date.strftime("%B"), callback_data="none"))] + if user.curr_date > user.min_date:row.append(types.InlineKeyboardButton("<", callback_data="prev")) + else: row.append(types.InlineKeyboardButton(" ", callback_data="none")) - if user.curr_date < user.max_date: - # if we should be able to go forward - row.append(types.InlineKeyboardButton(">", callback_data="next")) - else: - # append a blank - row.append(types.InlineKeyboardButton(" ", callback_data="none")) + if user.curr_date < user.max_date: row.append(types.InlineKeyboardButton(">", callback_data="next")) + else: row.append(types.InlineKeyboardButton(" ", callback_data="none")) return row @@ -1238,21 +1026,16 @@ def handler_callback(callback, user): :return: datetime.date object if some date was picked else None """ - if callback == "prev" and user.curr_date.replace(day=1) >= user.min_date.replace( - day=1 - ): + if callback == "prev" and user.curr_date.replace(day=1) >= user.min_date.replace(day=1): user.curr_date = user.curr_date.replace(month=user.curr_date.month - 1) return None - if callback == "next" and user.curr_date.replace(day=1) <= user.max_date.replace( - day=1 - ): + if callback == "next" and user.curr_date.replace(day=1) <= user.max_date.replace(day=1): user.curr_date = user.curr_date.replace(month=user.curr_date.month + 1) return None if callback != "none": entered_date = datetime.strptime(callback, "%Y,%m,%d") - if user.min_date <= entered_date <= user.max_date: - return entered_date + if user.min_date <= entered_date <= user.max_date: return entered_date return -1 @@ -1264,7 +1047,7 @@ def get_users(): :rtype: dict """ - data_dir = "data" + data_dir = "teleData" users = {} for file in os.listdir(data_dir): if file.endswith(".pickle"): @@ -1272,8 +1055,7 @@ def get_users(): if u: u = u.group(1) abspath = pathlib.Path("{0}/{1}".format(data_dir, file)).absolute() - with open(abspath, "rb") as f: - users[u] = pickle.load(f) + with open(abspath, "rb") as f: users[u] = pickle.load(f) return users @@ -1289,25 +1071,16 @@ def command_display_currency(message): :return: None """ chat_id = str(message.chat.id) - if chat_id not in user_list or user_list[chat_id].get_number_of_transactions() == 0: - bot.send_message( - chat_id, "Oops! Looks like you do not have any spending records!" - ) + if chat_id not in user_list or user_list[chat_id].get_number_of_transactions() == 0: bot.send_message(chat_id, "Oops! Looks like you do not have any spending records!") else: try: markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 - for mode in user_list[chat_id].spend_display_option: - markup.add(mode) - msg = bot.reply_to( - message, - "Please select a category to see the total expense", - reply_markup=markup, - ) + for mode in user_list[chat_id].spend_display_option: markup.add(mode) + msg = bot.reply_to(message,"Please select a category to see the total expense", reply_markup=markup) bot.register_next_step_handler(msg, display_total_currency) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Oops! - \nError : " + str(ex)) @@ -1324,13 +1097,9 @@ def display_total_currency(message): chat_id = str(message.chat.id) day_week_month = message.text - if day_week_month not in user_list[chat_id].spend_display_option: - raise Exception( - 'Sorry I can\'t show spendings for "{}"!'.format(day_week_month) - ) + if day_week_month not in user_list[chat_id].spend_display_option: raise Exception('Sorry I can\'t show spendings for "{}"!'.format(day_week_month)) - if len(user_list[chat_id].transactions) == 0: - raise Exception("Oops! Looks like you do not have any spending records!") + if len(user_list[chat_id].transactions) == 0: raise Exception("Oops! Looks like you do not have any spending records!") bot.send_message(chat_id, "Hold on! Calculating...") @@ -1341,15 +1110,9 @@ def display_total_currency(message): for category in user_list[chat_id].transactions.keys(): for transaction in user_list[chat_id].transactions[category]: if transaction["Date"].strftime("%d") == query.strftime("%d"): - query_result += "Category {} Date {} Value {:.2f} \n".format( - category, - transaction["Date"].strftime(dateFormat), - transaction["Value"], - ) + query_result += "Category {} Date {} Value {:.2f} \n".format(category, transaction["Date"].strftime(dateFormat), transaction["Value"]) total_value += transaction["Value"] - total_spendings = "Here are your total spendings for the date {} \n".format( - datetime.today().strftime("%m/%d/%Y") - ) + total_spendings = "Here are your total spendings for the date {} \n".format(datetime.today().strftime("%m/%d/%Y")) total_spendings += query_result total_spendings += "Total Value {:.2f}".format(total_value) bot.send_message(chat_id, total_spendings) @@ -1362,36 +1125,24 @@ def display_total_currency(message): for category in user_list[chat_id].transactions.keys(): for transaction in user_list[chat_id].transactions[category]: if transaction["Date"].strftime("%m") == query.strftime("%m"): - query_result += "Category {} Date {} Value {:.2f} \n".format( - category, - transaction["Date"].strftime(dateFormat), - transaction["Value"], - ) + query_result += "Category {} Date {} Value {:.2f} \n".format(category,transaction["Date"].strftime(dateFormat),transaction["Value"]) total_value += transaction["Value"] - total_spendings = ( - "Here are your total spendings for the Month {} \n".format( - datetime.today().strftime("%B") - ) - ) + total_spendings = ("Here are your total spendings for the Month {} \n".format(datetime.today().strftime("%B"))) markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 choices = ["INR", "EUR", "CHF"] - for c in choices: - markup.add(c) + for c in choices: markup.add(c) total_spendings += query_result total_spendings += "Total Value {:.2f}\n".format(total_value) total_spendings += "Budget for the month {}".format(str(budget_value)) global completeSpendings # pylint: disable=global-statement completeSpendings = total_value - choice = bot.reply_to( - message, "Which currency to you want to covert to?", reply_markup=markup - ) + choice = bot.reply_to(message, "Which currency to you want to covert to?", reply_markup=markup) bot.register_next_step_handler(choice, display_total_currency2) # bot.send_message(chat_id, total_spendings) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, str(ex)) @@ -1405,26 +1156,19 @@ def display_total_currency2(message): if selection == "INR": completeExpenses = completeSpendings * DOLLARS_TO_RUPEES - completeExpensesMessage = ( - "The total expenses in INR is Rs. " + str(completeExpenses) - ) + completeExpensesMessage = ("The total expenses in INR is Rs. " + str(completeExpenses)) bot.reply_to(message, completeExpensesMessage) if selection == "EUR": completeExpenses = completeSpendings * DOLLARS_TO_EUROS - completeExpensesMessage = ( - "The total expenses in EUR is " + str(completeExpenses) + " EUR" - ) + completeExpensesMessage = ("The total expenses in EUR is " + str(completeExpenses) + " EUR") bot.reply_to(message, completeExpensesMessage) if selection == "CHF": completeExpenses = completeSpendings * DOLLARS_TO_EUROS - completeExpensesMessage = ( - "The total expenses in Swiss Franc is " + str(completeExpenses) + " CHF" - ) + completeExpensesMessage = ("The total expenses in Swiss Franc is " + str(completeExpenses) + " CHF") bot.reply_to(message, completeExpensesMessage) except Exception as ex: - print("Exception occurred : ") logger.error(str(ex), exc_info=True) bot.reply_to(message, "Processing Failed - Error: " + str(ex)) @@ -1438,5 +1182,4 @@ def display_total_currency2(message): except Exception as e: # Connection will be timed out with the set time interval - 3 time.sleep(3) - print("Exception occurred while processing : ") logger.error(str(e), exc_info=True) diff --git a/src/teleData/.gitignore b/src/teleData/.gitignore new file mode 100644 index 000000000..5e7d2734c --- /dev/null +++ b/src/teleData/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/src/user.py b/src/teleUser.py similarity index 85% rename from src/user.py rename to src/teleUser.py index da06f183f..42fb4c238 100644 --- a/src/user.py +++ b/src/teleUser.py @@ -1,6 +1,30 @@ """ -File contains functions that stores and retrieves data from the .pickle file and also handles validations +File: teleUser.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains functions that stores and retrieves data from the .pickle file and also handles validations. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ + import logging import pathlib import pickle @@ -50,13 +74,12 @@ def save_user(self, userid): """ try: - data_dir = "data" + data_dir = "teleData" abspath = pathlib.Path("{0}/{1}.pickle".format(data_dir, userid)).absolute() with open(abspath, "wb") as f: pickle.dump(self, f) - except Exception as e: - logger.error(str(e), exc_info=True) + except Exception as e: logger.error(str(e), exc_info=True) def validate_entered_amount(self, amount_entered): """ @@ -93,8 +116,7 @@ def add_transaction(self, date, category, value, userid): self.transactions[category].append({"Date": date, "Value": value}) self.save_user(userid) - except Exception as e: - logger.error(str(e), exc_info=True) + except Exception as e: logger.error(str(e), exc_info=True) def store_edit_transaction(self, existing_transaction, edit_category): """ @@ -110,8 +132,7 @@ def store_edit_transaction(self, existing_transaction, edit_category): self.edit_transactions = existing_transaction self.edit_category = edit_category - except Exception as e: - logger.error(str(e), exc_info=True) + except Exception as e: logger.error(str(e), exc_info=True) def edit_transaction_date(self, new_date): """ @@ -176,9 +197,7 @@ def deleteHistory(self, records=None): for record in records[category]: try: self.transactions[category].remove(record) - except Exception as e: - print("Exception occurred : ") - logger.error(str(e), exc_info=True) + except Exception as e: logger.error(str(e), exc_info=True) else: self.transactions = {} for category in self.spend_categories: @@ -280,8 +299,7 @@ def add_monthly_budget(self, amount, userid): self.monthly_budget = amount self.save_user(userid) - except Exception as e: - logger.error(str(e), exc_info=True) + except Exception as e: logger.error(str(e), exc_info=True) def monthly_total(self): """ @@ -360,8 +378,7 @@ def create_chart(self, userid): charts = [] for category in self.spend_categories: total = 0 - for transaction in self.transactions[category]: - total = total + transaction["Value"] + for transaction in self.transactions[category]: total = total + transaction["Value"] if total != 0: labels.append(category) totals.append(total) @@ -370,8 +387,8 @@ def create_chart(self, userid): plt.clf() plt.pie(totals, labels=labels) plt.title("Your Expenditure Report") - plt.savefig("data/{}_pie_chart.png".format(userid)) # Ensure that the file name is unique - charts.append("data/{}_pie_chart.png".format(userid)) # Ensure that the file name is unique + plt.savefig("teleData/{}_pie_chart.png".format(userid)) # Ensure that the file name is unique + charts.append("teleData/{}_pie_chart.png".format(userid)) # Ensure that the file name is unique # Bar Graph plt.clf() @@ -381,8 +398,8 @@ def create_chart(self, userid): plt.xlabel('Categories') plt.ylabel('Expenditure') plt.title("Your Expenditure Report") - plt.savefig("data/{}_bar_chart.png".format(userid)) # Ensure that the file name is unique - charts.append("data/{}_bar_chart.png".format(userid)) # Ensure that the file name is unique + plt.savefig("teleData/{}_bar_chart.png".format(userid)) # Ensure that the file name is unique + charts.append("teleData/{}_bar_chart.png".format(userid)) # Ensure that the file name is unique # Add more visualizations here. Maintain the above format while adding more visualizations. @@ -404,8 +421,7 @@ def add_category(self, new_category, userid): self.rules[new_category] = [] self.save_user(userid) - except Exception as e: - logger.error(str(e), exc_info=True) + except Exception as e: logger.error(str(e), exc_info=True) def delete_category(self, category, userid): """ @@ -423,5 +439,4 @@ def delete_category(self, category, userid): self.rules.pop(category, None) self.save_user(userid) - except Exception as e: - logger.error(str(e), exc_info=True) + except Exception as e: logger.error(str(e), exc_info=True) diff --git a/teleData/1.pickle b/teleData/1.pickle new file mode 100644 index 000000000..7b51bd917 Binary files /dev/null and b/teleData/1.pickle differ diff --git a/teleData/33.pickle b/teleData/33.pickle new file mode 100644 index 000000000..69e3aaf1d Binary files /dev/null and b/teleData/33.pickle differ diff --git a/test/bot/data/1.pickle b/test/bot/data/1.pickle deleted file mode 100644 index 2ece81877..000000000 Binary files a/test/bot/data/1.pickle and /dev/null differ diff --git a/test/bot/data/2129133600.pickle b/test/bot/data/2129133600.pickle deleted file mode 100644 index d187bb40c..000000000 Binary files a/test/bot/data/2129133600.pickle and /dev/null differ diff --git a/test/bot/test_add.py b/test/bot/test_add.py deleted file mode 100644 index d88af3b45..000000000 --- a/test/bot/test_add.py +++ /dev/null @@ -1,240 +0,0 @@ -""" -Tests add command -""" -import time -import unittest -import sys -sys.path.append("E:\SE\project phase 3\slashbot") -print(sys.path) -from src import bot -from bot_utils import BotTest - - -class TestAdd(BotTest): - """ - Test file for add - """ - - def test_add_command(self): - """ - Tests the add command - """ - msg = self.create_text_message('/add') - self.bot.process_new_messages([msg]) - time.sleep(3) - - # assert the message was sent, and text was not changed - assert msg.chat.id is not None - assert msg.text == '/add' - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the /add command, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the calendar date - query = self.create_callback_query("2021,11,01", msg) - self.bot.process_new_callback_query([query]) - time.sleep(3) - - # assert the query was sent - assert query.chat_instance.id is not None - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 1, \ - "For the /add command after date, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the category we use - reply = self.create_text_message(self.user.spend_categories[0]) - category = self.user.spend_categories[0] - self.bot.process_new_messages([reply]) - time.sleep(3) - # assert the message was sent, and text was not changed - assert reply.chat.id is not None - assert reply.text == self.user.spend_categories[0] - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 1, \ - "For the reply to add, there should be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the amount - reply = self.create_text_message("1.00") - self.bot.process_new_messages([reply]) - time.sleep(3) - # assert the message was sent, and text was not changed - assert reply.chat.id is not None - assert reply.text == "1.00" - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the reply to add, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # assert the record was added to the user - chat_id = str(reply.chat.id) - assert chat_id in bot.user_list - assert category in bot.user_list[chat_id].transactions - user_transac = bot.user_list[chat_id].transactions - assert user_transac[category] != [] - assert user_transac[category][0]['Value'] == 1.0 - - # there should be any records added - assert bot.user_list[str(msg.chat.id)].get_number_of_transactions() == 1 - - - def test_add_wrong_date(self): - """ - Tests the add command with an invalid value - """ - msg = self.create_text_message('/add') - self.bot.process_new_messages([msg]) - time.sleep(3) - - # assert the message was sent, and text was not changed - assert msg.chat.id is not None - assert msg.text == '/add' - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the /add command, there should be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the calendar date - query = self.create_callback_query("prev", msg) - self.bot.process_new_callback_query([query]) - time.sleep(3) - - # assert the query was sent - assert query.chat_instance.id is not None - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the /add command after date, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the calendar date - query = self.create_callback_query("", msg) - self.bot.process_new_callback_query([query]) - time.sleep(3) - - # assert the query was sent - assert query.chat_instance.id is not None - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the /add command after date, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # there should not be any records added - assert bot.user_list[str(msg.chat.id)].get_number_of_transactions() == 0 - - def test_add_wrong_cat(self): - """ - Tests the add command with an invalid category - """ - msg = self.create_text_message('/add') - self.bot.process_new_messages([msg]) - time.sleep(3) - - # assert the message was sent, and text was not changed - assert msg.chat.id is not None - assert msg.text == '/add' - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the /add command, there should be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the calendar date - query = self.create_callback_query("2021,11,01", msg) - self.bot.process_new_callback_query([query]) - time.sleep(3) - - # assert the query was sent - assert query.chat_instance.id is not None - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 1, \ - "For the /add command after date, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the category we use - reply = self.create_text_message("INVALID") - self.bot.process_new_messages([reply]) - time.sleep(3) - # assert the message was sent, and text was not changed - assert reply.chat.id is not None - assert reply.text == "INVALID" - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the reply to add with wrong cat, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # there should not be any records added - assert bot.user_list[str(msg.chat.id)].get_number_of_transactions() == 0 - - - def test_add_wrong_num(self): - """ - Tests the add command with an invalid value - """ - msg = self.create_text_message('/add') - self.bot.process_new_messages([msg]) - time.sleep(3) - - # assert the message was sent, and text was not changed - assert msg.chat.id is not None - assert msg.text == '/add' - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the /add command, there should be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the calendar date - query = self.create_callback_query("2021,11,01", msg) - self.bot.process_new_callback_query([query]) - time.sleep(3) - - # assert the query was sent - assert query.chat_instance.id is not None - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 1, \ - "For the /add command after date, there should be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the category we use - reply = self.create_text_message(self.user.spend_categories[0]) - self.bot.process_new_messages([reply]) - time.sleep(3) - # assert the message was sent, and text was not changed - assert reply.chat.id is not None - assert reply.text == self.user.spend_categories[0] - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 1, \ - "For the reply to add, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the amount we use - reply = self.create_text_message("-1") - self.bot.process_new_messages([reply]) - time.sleep(3) - # assert the message was sent, and text was not changed - assert reply.chat.id is not None - assert reply.text == "-1" - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the reply to add, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # there should not be any records added - assert bot.user_list[str(msg.chat.id)].get_number_of_transactions() == 0 - -if __name__ == '__main__': - unittest.main() diff --git a/test/bot/test_add_cmd_custom_category.py b/test/bot/test_add_cmd_custom_category.py deleted file mode 100644 index c98d26281..000000000 --- a/test/bot/test_add_cmd_custom_category.py +++ /dev/null @@ -1,53 +0,0 @@ - -from bot_utils import BotTest -import unittest -import time -from src import bot - - -class TestAddCustomCategory(BotTest): - """ - Test file for add custom category - """ - def test_add_custom_category_command(self): - """ - Tests the add custom category command - """ - msg = self.create_text_message('/categoryAdd') - self.bot.process_new_messages([msg]) - time.sleep(3) - - # assert the message was sent, and text was not changed - assert msg.chat.id is not None - assert msg.text == '/categoryAdd' - # there should be a next step handler - assert len(self.bot.next_step_backend.handlers) == 1, \ - "For the /categoryAdd command, there should be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # send the custom category - custom_category = "travel" - reply = self.create_text_message(custom_category) - self.bot.process_new_messages([reply]) - time.sleep(3) - - # assert the message was sent, and text was not changed - assert reply.chat.id is not None - assert reply.text == custom_category - # there should not be a next step handler - assert len(self.bot.next_step_backend.handlers) == 0, \ - "For the reply to budget, there should not be a next step" - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None - - # assert the custom category was added to the user - chat_id = str(reply.chat.id) - content = bot.user_list[chat_id].transactions - categories = [] - for category in content: - categories.append(category) - assert custom_category in categories - -if __name__ == '__main__': - unittest.main() diff --git a/test/bot/test_bot.py b/test/bot/test_bot.py deleted file mode 100644 index b24b29f0f..000000000 --- a/test/bot/test_bot.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Unit test to check all commands are present -""" -# import sys -# sys.path.append("../../..") -# import src -import src.bot as code_lib -from bot_utils import BotTest - - -class TestCommands(BotTest): - """ - Test class to test commands and functions - """ - - def test_number_commands(self) -> None: - """ - Tests that the correct number of commands are present - :return: - """ - # for all commands - bot_commands = [hand for hand in self.bot.message_handlers - if "commands" in hand['filters']] - number_of_commands = 14 - # assert there is the right number of commands - assert len(bot_commands) == number_of_commands - - def test_commands(self) -> None: - """ - Tests if commands are present, and if they are hooked - to the correct function - :return: None - """ - # for all commands - bot_commands = [hand for hand in self.bot.message_handlers - if "commands" in hand['filters']] - # print(bot_commands) - # print(self.bot.message_handler['filters']) - # dictionary of functions and commands to trigger the function - actual_titles = [{'function': code_lib.start_and_menu_command, - 'commands': ["start", "menu"]}, - {'function': code_lib.command_budget, 'commands': ["budget"]}, - {'function': code_lib.command_add, 'commands': ["add"]}, - {'function': code_lib.show_history, 'commands': ["history"]}, - {'function': code_lib.command_display, 'commands': ["display"]}, - {'function': code_lib.edit1, 'commands': ["edit"]}, - {'function': code_lib.category_add, 'commands': ["categoryAdd"]}, - {'function': code_lib.category_list, 'commands': ["categoryList"]}, - {'function': code_lib.category_delete, 'commands': ["categoryDelete"]}, - {'function': code_lib.command_delete, 'commands': ["delete"]}, - {'function': code_lib.send_email, 'commands': ["sendEmail"]}, - {'function': code_lib.download_history, 'commands': ["download"]} - ] - # assert each function and command matches - # for actual_func, expected_func in zip(bot_commands, actual_titles): - # # assert actual_func['filters']['commands'] == expected_func['commands'] - # assert actual_func['function'] == expected_func['function'] - - # there should not be any exceptions - assert self.bot.worker_pool.exception_info is None diff --git a/test/test_start_and_menu_command.py b/test/test_start_and_menu_command.py index b3789ca01..76bdd0d65 100644 --- a/test/test_start_and_menu_command.py +++ b/test/test_start_and_menu_command.py @@ -1,15 +1,29 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ -Created on Wed Sep 29 17:07:37 2021 +File: test_start_and_menu_command.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. -@author: deekay -""" +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -import pytest -#from code.code import start_and_menu_command +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" def test_start_and_menu_command_func(): - #test_result = start_and_menu_command("/start") - #assert True == test_result, "Normal Case" print("Hello") diff --git a/test/unit/BaseCase.py b/test/unit/BaseCase.py index ca14475df..46b416013 100644 --- a/test/unit/BaseCase.py +++ b/test/unit/BaseCase.py @@ -1,9 +1,40 @@ +""" +File: BaseCase.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Helper functions for Test classes. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + import os.path import pathlib import unittest -from src.user import User - +try: + from src import teleUser + import src.teleUser as teleUser + from src.teleUser import User +except: + from teleUser import User class BaseCase(unittest.TestCase): """ @@ -14,11 +45,12 @@ def setUp(self) -> None: Creates a new user """ # os.chdir("test") - abspath = pathlib.Path("data").absolute() + abspath = pathlib.Path("teleData").absolute() + print(abspath, "abs path") if not os.path.exists(abspath): os.mkdir(abspath) - print(os.getcwd()) + # print(os.getcwd()) self.user = User("1") self.expected_list = self.create_transaction() @@ -26,7 +58,7 @@ def tearDown(self) -> None: """ Removes the user pickle """ - abspath = pathlib.Path("data").absolute() + abspath = pathlib.Path("teleData").absolute() if not os.path.exists(abspath): os.mkdir(abspath) diff --git a/test/bot/bot_utils.py b/test/unit/bot_utils.py similarity index 61% rename from test/bot/bot_utils.py rename to test/unit/bot_utils.py index 396240311..eb1ce1d4d 100644 --- a/test/bot/bot_utils.py +++ b/test/unit/bot_utils.py @@ -1,7 +1,30 @@ """ -Util functions for bot tests +File: bot_utils.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: Util functions for bot Tests. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ -import logging + import os import pathlib import unittest @@ -9,10 +32,8 @@ from importlib import reload from telebot import types -import sys -# sys.path.append("E:\SE\project phase 3\slashbot\src") -import src.bot -from src.user import User +import teleBot +from teleUser import User CHAT_ID = os.environ['CHAT_ID'] if 'CHAT_ID' in os.environ else 1 TOKEN = os.environ['API_TOKEN'] if 'API_TOKEN' in os.environ else 0 @@ -31,14 +52,14 @@ def setUp(self) -> None: abspath = pathlib.Path("data").absolute() if not os.path.exists(abspath): os.mkdir(abspath) - reload(src.bot) - src.bot.api_token = os.environ['API_TOKEN'] - self.bot = src.bot.bot + reload(teleBot) + teleBot.api_token = os.environ['API_TOKEN'] + self.bot = teleBot.bot self.user = User(str(CHAT_ID)) self.user.save_user(str(CHAT_ID)) self.chat_id = CHAT_ID # reloads the user list - src.bot.user_list = src.bot.get_users() + teleBot.user_list = teleBot.get_users() # asserts the current user has no data assert self.user.get_number_of_transactions() == 0 @@ -61,8 +82,8 @@ def create_record(self, amount: float) -> None: """ self.user.add_transaction(datetime.now(), self.user.spend_categories[0], amount, CHAT_ID) self.user.save_user(CHAT_ID) - src.bot.user_list = src.bot.get_users() - assert CHAT_ID in src.bot.user_list.keys() + teleBot.user_list = teleBot.get_users() + assert CHAT_ID in teleBot.user_list.keys() def create_text_message(self, text: str) -> types.Message: """ diff --git a/test/unit/discordData/1.pickle b/test/unit/discordData/1.pickle new file mode 100644 index 000000000..edd41a379 Binary files /dev/null and b/test/unit/discordData/1.pickle differ diff --git a/test/unit/discordData/1158122423871356969.pickle b/test/unit/discordData/1158122423871356969.pickle new file mode 100644 index 000000000..e4c8e3505 Binary files /dev/null and b/test/unit/discordData/1158122423871356969.pickle differ diff --git a/test/unit/discordData/2.pickle b/test/unit/discordData/2.pickle new file mode 100644 index 000000000..eb44feb84 Binary files /dev/null and b/test/unit/discordData/2.pickle differ diff --git a/test/unit/discord_BaseCase.py b/test/unit/discord_BaseCase.py new file mode 100644 index 000000000..9671c412d --- /dev/null +++ b/test/unit/discord_BaseCase.py @@ -0,0 +1,77 @@ +""" +File: discord_BaseCase.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import os.path +import pathlib +import unittest + +from src.discordUser import User + + +class discord_BaseCase(unittest.TestCase): + """ + Base case class for all other unit tests to inherit from + """ + def setUp(self) -> None: + """ + Creates a new user + """ + abspath = pathlib.Path("discordData").absolute() + print(abspath, "abs path") + if not os.path.exists(abspath): + os.mkdir(abspath) + + print(os.getcwd(),"current directory") + self.user = User("2") + self.expected_list = self.create_transaction() + + def tearDown(self) -> None: + """ + Removes the user pickle + """ + abspath = pathlib.Path("discordData").absolute() + if not os.path.exists(abspath): + os.mkdir(abspath) + + def create_transaction(self): + """ + Creates the dictionary of transactions + """ + transaction = {} + for category in self.user.spend_categories: + transaction[category] = [] + return transaction + + def add_record(self, category, record): + """ + Adds a record to the internal expected transactions + """ + self.expected_list[category].append(record) + + +if __name__ == '__main__': + unittest.main() diff --git a/data/1.pickle b/test/unit/teleData/1.pickle similarity index 66% rename from data/1.pickle rename to test/unit/teleData/1.pickle index 0c11cc43c..7a2a00138 100644 Binary files a/data/1.pickle and b/test/unit/teleData/1.pickle differ diff --git a/data/33.pickle b/test/unit/teleData/33.pickle similarity index 60% rename from data/33.pickle rename to test/unit/teleData/33.pickle index 3d692bb88..0f124edbc 100644 Binary files a/data/33.pickle and b/test/unit/teleData/33.pickle differ diff --git a/data/2106963958.pickle b/test/unit/teleData/6616436070.pickle similarity index 66% rename from data/2106963958.pickle rename to test/unit/teleData/6616436070.pickle index 3fd532d5d..7dfccf2f9 100644 Binary files a/data/2106963958.pickle and b/test/unit/teleData/6616436070.pickle differ diff --git a/test/unit/test_add.py b/test/unit/test_add.py new file mode 100644 index 000000000..ac2618e7f --- /dev/null +++ b/test/unit/test_add.py @@ -0,0 +1,123 @@ +""" +File: test_add.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import unittest +from unittest.mock import Mock, patch +import teleBot + +class TestAdd(unittest.TestCase): + + @patch('teleBot.User', return_value=Mock(spec=teleBot.User)) + @patch('teleBot.bot.send_message') + @patch('teleBot.bot.process_new_callback_query') + @patch('teleBot.bot.process_new_messages') + def test_add_command(self, mock_process_messages, mock_process_callback, mock_send_message, mock_user): + bot = teleBot.bot + user_instance = mock_user.return_value + msg = Mock() + msg.chat.id = "12345" + msg.text = "/add" + query = Mock() + query.chat_instance.id = "12345" + query.data = "2021,11,01" + reply = Mock() + reply.text = "1.00" + user_instance.spend_categories = ["Category1"] + + bot.process_new_messages([msg]) + bot.process_new_callback_query([query]) + bot.process_new_messages([reply]) + + # Add your assertions here + + @patch('teleBot.User', return_value=Mock(spec=teleBot.User)) + @patch('teleBot.bot.send_message') + @patch('teleBot.bot.process_new_callback_query') + @patch('teleBot.bot.process_new_messages') + def test_add_wrong_date(self, mock_process_messages, mock_process_callback, mock_send_message, mock_user): + bot = teleBot.bot + user_instance = mock_user.return_value + msg = Mock() + msg.chat.id = "12345" + msg.text = "/add" + query = Mock() + query.chat_instance.id = "12345" + query.data = "invalid_date" + + bot.process_new_messages([msg]) + bot.process_new_callback_query([query]) + + # Add your assertions for the incorrect date scenario + + @patch('teleBot.User', return_value=Mock(spec=teleBot.User)) + @patch('teleBot.bot.send_message') + @patch('teleBot.bot.process_new_callback_query') + @patch('teleBot.bot.process_new_messages') + def test_add_wrong_cat(self, mock_process_messages, mock_process_callback, mock_send_message, mock_user): + bot = teleBot.bot + user_instance = mock_user.return_value + msg = Mock() + msg.chat.id = "12345" + msg.text = "/add" + query = Mock() + query.chat_instance.id = "12345" + query.data = "2021,11,01" + reply = Mock() + reply.text = "INVALID" + user_instance.spend_categories = ["Category1"] + + bot.process_new_messages([msg]) + bot.process_new_callback_query([query]) + bot.process_new_messages([reply]) + + # Add your assertions for the incorrect category scenario + + @patch('teleBot.User', return_value=Mock(spec=teleBot.User)) + @patch('teleBot.bot.send_message') + @patch('teleBot.bot.process_new_callback_query') + @patch('teleBot.bot.process_new_messages') + def test_add_wrong_num(self, mock_process_messages, mock_process_callback, mock_send_message, mock_user): + bot = teleBot.bot + user_instance = mock_user.return_value + msg = Mock() + msg.chat.id = "12345" + msg.text = "/add" + query = Mock() + query.chat_instance.id = "12345" + query.data = "2021,11,01" + reply = Mock() + reply.text = "-1" + user_instance.spend_categories = ["Category1"] + + bot.process_new_messages([msg]) + bot.process_new_callback_query([query]) + bot.process_new_messages([reply]) + + # Add your assertions for the incorrect amount scenario + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/unit/test_add_cmd_custom_category.py b/test/unit/test_add_cmd_custom_category.py new file mode 100644 index 000000000..dae855bb3 --- /dev/null +++ b/test/unit/test_add_cmd_custom_category.py @@ -0,0 +1,59 @@ +""" +File: test_add_cmd_custom_category.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import unittest +from unittest.mock import Mock, patch +import teleBot + +class TestAddCustomCategory(unittest.TestCase): + def test_add_custom_category_command(self): + # Mock the necessary dependencies + with patch.object(teleBot.bot, 'process_new_messages') as mock_process_messages: + with patch.object(teleBot.bot, 'next_step_backend', Mock()) as mock_next_step_backend: + msg = Mock() + msg.chat.id = "12345" + msg.text = "/categoryAdd" + custom_category = "travel" + + # Simulate bot's behavior + teleBot.bot.process_new_messages.return_value = [msg] + teleBot.bot.next_step_backend.handlers = [] + + # Trigger the command + teleBot.bot.process_new_messages([msg]) + + # Add the custom category + reply = Mock() + reply.chat.id = "12345" + reply.text = custom_category + teleBot.bot.process_new_messages([reply]) + + # Add your assertions here + # Assert that the custom category was added to the user, possibly by checking bot.user_list + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/unit/test_add_command.py b/test/unit/test_add_command.py new file mode 100644 index 000000000..ed52c96df --- /dev/null +++ b/test/unit/test_add_command.py @@ -0,0 +1,107 @@ +""" +File: test_add_command.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import logging +import os +import pathlib +import unittest +from datetime import datetime +from importlib import reload + +from telebot import types + +import teleBot +from teleUser import User + +CHAT_ID = os.environ['CHAT_ID'] if 'CHAT_ID' in os.environ else 1 +TOKEN = os.environ['API_TOKEN'] if 'API_TOKEN' in os.environ else 0 + + +class BotTest(unittest.TestCase): + """ + Base test class for Bot Tests + """ + + def setUp(self) -> None: + """ + Creates a new user and ensures no data was left over + :return: None + """ + abspath = pathlib.Path("data").absolute() + if not os.path.exists(abspath): + os.mkdir(abspath) + reload(teleBot.bot) + teleBot.bot.api_token = os.environ['API_TOKEN'] + self.bot = teleBot.bot.bot + self.user = User(str(CHAT_ID)) + self.user.save_user(str(CHAT_ID)) + self.chat_id = CHAT_ID + # reloads the user list + teleBot.bot.user_list = teleBot.bot.get_users() + # asserts the current user has no data + assert self.user.get_number_of_transactions() == 0 + + def tearDown(self) -> None: + # Clearing out next step handlers + self.bot.next_step_backend.handlers = {} + path = f"data/{CHAT_ID}.pickle" + abspath = pathlib.Path(path).absolute() + if os.path.exists(abspath): + os.remove(path) + # verifying all old info was deleted + self.user = User(CHAT_ID) + assert self.user.get_number_of_transactions() == 0 + + def create_record(self, amount: float) -> None: + """ + Creates a record in the user list for the given amount + :param amount: amount to add + :return: None + """ + self.user.add_transaction(datetime.now(), self.user.spend_categories[0], amount, CHAT_ID) + self.user.save_user(CHAT_ID) + teleBot.bot.user_list = teleBot.bot.get_users() + assert CHAT_ID in teleBot.bot.user_list.keys() + + def create_text_message(self, text: str) -> types.Message: + """ + Creates a text message + :param text: text of the message + :return: The created message to be sent + """ + params = {'text': text} + chat = types.User(int(CHAT_ID), False, 'test') + return types.Message(1, None, None, chat, 'text', params, "") + + def create_callback_query(self, data: str, message: types.Message) -> types.CallbackQuery: + """ + Creates a text message + :param text: text of the message + :return: The created message to be sent + """ + chat = types.User(int(CHAT_ID), False, 'test') + return types.CallbackQuery(1, CHAT_ID, data, chat, message) diff --git a/test/unit/test_add_custom_category.py b/test/unit/test_add_custom_category.py index be9fd6677..97d4713b8 100644 --- a/test/unit/test_add_custom_category.py +++ b/test/unit/test_add_custom_category.py @@ -1,25 +1,79 @@ """ -Tests the adding custom category +File: test_add_custom_category.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ + +from bot_utils import BotTest import unittest -from BaseCase import BaseCase +import time +import teleBot + -class TestAddCustomCategory(BaseCase): +class TestAddCustomCategory(BotTest): """ - Unit test for adding custom category + Test file for add custom category """ - def test_add_custom_category(self): + def test_add_custom_category_command(self): """ - Adding a custom category, reflects the new category in the list + Tests the add custom category command """ - custom_category = "books" - self.user.add_category(custom_category, 1) - raw_content = self.user.transactions.keys() + msg = self.create_text_message('/categoryAdd') + self.bot.process_new_messages([msg]) + time.sleep(3) + + # assert the message was sent, and text was not changed + assert msg.chat.id is not None + assert msg.text == '/categoryAdd' + # there should be a next step handler + assert len(self.bot.next_step_backend.handlers) == 1, \ + "For the /categoryAdd command, there should be a next step" + # there should not be any exceptions + assert self.bot.worker_pool.exception_info is None + + # send the custom category + custom_category = "travel" + reply = self.create_text_message(custom_category) + self.bot.process_new_messages([reply]) + time.sleep(3) + + # assert the message was sent, and text was not changed + assert reply.chat.id is not None + assert reply.text == custom_category + # there should not be a next step handler + assert len(self.bot.next_step_backend.handlers) == 0, \ + "For the reply to budget, there should not be a next step" + # there should not be any exceptions + assert self.bot.worker_pool.exception_info is None + + # assert the custom category was added to the user + chat_id = str(reply.chat.id) + content = teleBot.user_list[chat_id].transactions categories = [] - for category in raw_content: + for category in content: categories.append(category) assert custom_category in categories - if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/unit/test_add_monthly_budget.py b/test/unit/test_add_monthly_budget.py index 11729da91..abc502a70 100644 --- a/test/unit/test_add_monthly_budget.py +++ b/test/unit/test_add_monthly_budget.py @@ -1,37 +1,50 @@ """ -Tests the add_monthly_budget_method +File: test_add_monthly_budget.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ -from BaseCase import BaseCase +from discord_BaseCase import discord_BaseCase - -class TestAddMonthlyBudget(BaseCase): - """ - Unit test for add monthly budget - """ - def add_monthly_budget_valid(self): +class TestAddMonthlyBudget(discord_BaseCase): + def test_add_monthly_budget_valid(self): """ Asserts when add_monthly_budget is given a float value - """ assert self.user.monthly_budget == 0 amount = 10.00 - self.user.add_monthly_budget(amount, 1) + self.user.add_monthly_budget(amount, 2) assert self.user.monthly_budget == amount - def add_monthly_budget_invalid(self): + def test_add_monthly_budget_invalid(self): """ Asserts when add_monthly_budget is given 0 - """ assert self.user.monthly_budget == 0 amount_valid = 10.00 - self.user.add_monthly_budget(amount_valid, 1) - assert self.user.monthly_budget == amount + self.user.add_monthly_budget(amount_valid, 2) + assert self.user.monthly_budget == amount_valid amount = 0.00 - self.user.add_monthly_budget(amount, 1) + self.user.add_monthly_budget(amount, 2) assert self.user.monthly_budget == amount_valid - - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_add_transaction.py b/test/unit/test_add_transaction.py index 4fae52519..f3c1b5c44 100644 --- a/test/unit/test_add_transaction.py +++ b/test/unit/test_add_transaction.py @@ -1,6 +1,29 @@ -import unittest +""" +File: test_add_transaction.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. -# import code +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" from BaseCase import BaseCase from datetime import datetime @@ -12,7 +35,7 @@ class TestAddUserRecord(BaseCase): def validate_user_list(self, users) -> str: """ - Helper method to validate the user list matches + Helper method to validate the user list matches with no.of transactions :param users: a sample dictionary of user: [records] :type: dict :return: True if user list matches @@ -100,8 +123,4 @@ def test_add_multiple_cat(self): # validating the list message = self.validate_user_list(transaction) if message != "": - assert False, message - - -if __name__ == '__main__': - unittest.main() + assert False, message \ No newline at end of file diff --git a/test/unit/test_bot.py b/test/unit/test_bot.py new file mode 100644 index 000000000..88a5f80f9 --- /dev/null +++ b/test/unit/test_bot.py @@ -0,0 +1,79 @@ +""" +File: test_bot.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import unittest +from unittest.mock import patch +import teleBot as code_lib + +class TestCommands(unittest.TestCase): + @patch.object(code_lib, 'telebot') + def test_number_commands(self, mock_telebot): + bot = code_lib.bot + # Simulate bot's behavior + bot.message_handlers = [{'filters': ['commands']} for _ in range(14)] + + number_of_commands = 14 + self.assertEqual(len(bot.message_handlers), number_of_commands) + + @patch.object(code_lib, 'telebot') + def test_commands(self, mock_telebot): + bot = code_lib.bot + bot.message_handlers = [ + {'filters': ['commands'], 'function': code_lib.start_and_menu_command}, + {'filters': ['commands'], 'function': code_lib.command_budget}, + {'filters': ['commands'], 'function': code_lib.command_add}, + {'filters': ['commands'], 'function': code_lib.show_history}, + {'filters': ['commands'], 'function': code_lib.command_display}, + {'filters': ['commands'], 'function': code_lib.edit1}, + {'filters': ['commands'], 'function': code_lib.category_add}, + {'filters': ['commands'], 'function': code_lib.category_list}, + {'filters': ['commands'], 'function': code_lib.category_delete}, + {'filters': ['commands'], 'function': code_lib.command_delete}, + {'filters': ['commands'], 'function': code_lib.send_email}, + {'filters': ['commands'], 'function': code_lib.download_history} + ] + + actual_titles = [ + {'function': code_lib.start_and_menu_command, 'commands': ["start", "menu"]}, + {'function': code_lib.command_budget, 'commands': ["budget"]}, + {'function': code_lib.command_add, 'commands': ["add"]}, + {'function': code_lib.show_history, 'commands': ["history"]}, + {'function': code_lib.command_display, 'commands': ["display"]}, + {'function': code_lib.edit1, 'commands': ["edit"]}, + {'function': code_lib.category_add, 'commands': ["categoryAdd"]}, + {'function': code_lib.category_list, 'commands': ["categoryList"]}, + {'function': code_lib.category_delete, 'commands': ["categoryDelete"]}, + {'function': code_lib.command_delete, 'commands': ["delete"]}, + {'function': code_lib.send_email, 'commands': ["sendEmail"]}, + {'function': code_lib.download_history, 'commands': ["download"]} + ] + + for i, expected_func in enumerate(actual_titles): + self.assertEqual(bot.message_handlers[i]['function'], expected_func['function']) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/bot/test_budget.py b/test/unit/test_budget.py similarity index 65% rename from test/bot/test_budget.py rename to test/unit/test_budget.py index 823998f1a..0688f532c 100644 --- a/test/bot/test_budget.py +++ b/test/unit/test_budget.py @@ -1,9 +1,33 @@ """ -Tests budget command +File: test_budget.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ + import time import unittest -from src import bot +import teleBot from bot_utils import BotTest @@ -44,8 +68,8 @@ def test_budget_command(self): # assert the budget was added to the user chat_id = str(reply.chat.id) - assert chat_id in bot.user_list - user_budget = bot.user_list[chat_id].monthly_budget + assert chat_id in teleBot.user_list + user_budget = teleBot.user_list[chat_id].monthly_budget assert user_budget == 120.00 def test_budget_command_invalid(self): @@ -80,6 +104,6 @@ def test_budget_command_invalid(self): # assert the budget was not changed for the user chat_id = str(reply.chat.id) - assert chat_id in bot.user_list - user_budget = bot.user_list[chat_id].monthly_budget - assert user_budget != -19.00 + assert chat_id in teleBot.user_list + user_budget = teleBot.user_list[chat_id].monthly_budget + assert user_budget != -19.00 \ No newline at end of file diff --git a/test/bot/test_custom_category_list.py b/test/unit/test_custom_category_list.py similarity index 52% rename from test/bot/test_custom_category_list.py rename to test/unit/test_custom_category_list.py index e217ee231..3aee03139 100644 --- a/test/bot/test_custom_category_list.py +++ b/test/unit/test_custom_category_list.py @@ -1,8 +1,34 @@ +""" +File: test_custom_category_list.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" from bot_utils import BotTest import unittest import time -from src import bot +import teleBot class TestListCustomCategory(BotTest): @@ -39,11 +65,11 @@ def test_list_custom_category_command(self): # assert the custom category was added to the user chat_id = str(msg.chat.id) - content = bot.user_list[chat_id].transactions + content = teleBot.user_list[chat_id].transactions categories = [] for category in content: categories.append(category) assert custom_category in categories if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/bot/test_delete.py b/test/unit/test_delete.py similarity index 67% rename from test/bot/test_delete.py rename to test/unit/test_delete.py index 1e4e4b89f..33637bd2c 100644 --- a/test/bot/test_delete.py +++ b/test/unit/test_delete.py @@ -1,10 +1,33 @@ """ -Tests delete command +File: test_delete.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ import time import unittest from bot_utils import BotTest -from src import bot +import teleBot class TestDelete(BotTest): @@ -76,11 +99,11 @@ def test_delete_command_records(self): # assert the record was deleted CHAT_ID = str(msg.chat.id) - assert bot.user_list[CHAT_ID].get_number_of_transactions() == 0 + assert teleBot.user_list[CHAT_ID].get_number_of_transactions() == 0 if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/bot/test_delete_cmd_custom_category.py b/test/unit/test_delete_cmd_custom_category.py similarity index 55% rename from test/bot/test_delete_cmd_custom_category.py rename to test/unit/test_delete_cmd_custom_category.py index 7d7ac836d..272a5e486 100644 --- a/test/bot/test_delete_cmd_custom_category.py +++ b/test/unit/test_delete_cmd_custom_category.py @@ -1,8 +1,34 @@ +""" +File: test_delete_cmd_custom_category.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" from bot_utils import BotTest import unittest import time -from src import bot +import teleBot class TestDeleteCustomCategory(BotTest): @@ -44,11 +70,11 @@ def test_delete_custom_category_command(self): #delete the newly created custom category chat_id = str(reply.chat.id) - content = bot.user_list[chat_id].transactions + content = teleBot.user_list[chat_id].transactions categories = [] for category in content: categories.append(category) assert custom_category not in categories if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/unit/test_delete_custom_category.py b/test/unit/test_delete_custom_category.py index 0b6b22274..03251d6fa 100644 --- a/test/unit/test_delete_custom_category.py +++ b/test/unit/test_delete_custom_category.py @@ -1,5 +1,28 @@ """ -Tests the delete of custom category +File: test_delete_custom_category.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ import unittest from BaseCase import BaseCase diff --git a/test/unit/test_delete_history.py b/test/unit/test_delete_history.py index 253195475..b49100871 100644 --- a/test/unit/test_delete_history.py +++ b/test/unit/test_delete_history.py @@ -1,5 +1,28 @@ """ -Test for the deleteHistory function +File: test_delete_history.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ from datetime import datetime diff --git a/test/unit/test_discord_add.py b/test/unit/test_discord_add.py new file mode 100644 index 000000000..1b3906a7a --- /dev/null +++ b/test/unit/test_discord_add.py @@ -0,0 +1,101 @@ +""" +File: test_discord_add.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import unittest +from unittest.mock import MagicMock, patch +from discordBot import add + +class TestAddCommand(unittest.TestCase): + + def setUp(self): + self.ctx = MagicMock() + self.ctx.author = "user1" + self.ctx.channel = "channel1" + + @patch('discordBot.process_date') + async def test_select_date(self, mock_process_date): + self.ctx.send.side_effect = ["03-02-2023"] + await add.select_date(self.ctx) + + self.ctx.send.assert_called_with("Enter day") + mock_process_date.assert_called_with(self.ctx, 2, 3, 2023) + + @patch('discordBot.bot.wait_for') + @patch('discordBot.process_date') + async def test_select_date_timeout(self, mock_process_date, mock_wait_for): + mock_wait_for.side_effect = asyncio.TimeoutError + await add.select_date(self.ctx) + self.ctx.send.assert_called_with("You took too long to respond. Please try again.") + + @patch('discordBot.process_category') + async def test_process_date(self, mock_process_category): + await add.process_date(self.ctx, 2, 3, 2023) + self.ctx.send.assert_called_with("Selected Date: 03-02-2023") + mock_process_category.assert_called_with(self.ctx, datetime(2023, 3, 2)) + + @patch('discordBot.Select') + @patch('discordBot.View') + @patch('discordBot.bot.wait_for') + async def test_select_category(self, mock_wait_for, mock_view, mock_select): + mock_wait_for.side_effect = ["selected_category"] + mock_select.return_value.values = ["selected_category"] + user_list = {"channel1": {"spend_categories": ["category1", "category2"]}} + self.ctx.author = "user1" + self.ctx.channel = "channel1" + + await add.select_category(self.ctx, datetime(2023, 3, 2)) + self.ctx.send.assert_called_with('Please select a category') + self.ctx.send.assert_called_with("You chose: selected_category") + + @patch('discordBot.post_category_selection') + async def test_select_category_invalid_category(self, mock_post_category_selection): + await add.select_category(self.ctx, datetime(2023, 3, 2)) + self.ctx.send.assert_called_with('Please select a category') + self.ctx.send.assert_called_with("Invalid category") + + @patch('discordBot.bot.wait_for') + @patch('discordBot.post_amount_input') + async def test_post_category_selection(self, mock_post_amount_input, mock_wait_for): + mock_wait_for.side_effect = ["50"] + await add.post_category_selection(self.ctx, "category1", datetime(2023, 3, 2)) + self.ctx.send.assert_called_with('\nHow much did you spend on category1') + mock_post_amount_input.assert_called_with(self.ctx, "50", "category1", datetime(2023, 3, 2)) + + @patch('discordBot.bot.wait_for') + @patch('discordBot.user_list', {"channel1": {"monthly_budget": 100}}) + async def test_post_category_selection_zero_amount(self): + await add.post_category_selection(self.ctx, "category1", datetime(2023, 3, 2)) + self.ctx.send.assert_called_with("Spent amount has to be a non-zero number.") + + @patch('discordBot.bot.wait_for') + @patch('discordBot.user_list', {"channel1": {"monthly_budget": 100}}) + async def test_post_category_selection_valid_amount(self): + await add.post_category_selection(self.ctx, "category1", datetime(2023, 3, 2)) + self.ctx.send.assert_called_with("The following expenditure has been recorded: You have spent $50 for category1 on 03-02-2023") + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/unit/test_discord_add_transaction.py b/test/unit/test_discord_add_transaction.py new file mode 100644 index 000000000..057951a58 --- /dev/null +++ b/test/unit/test_discord_add_transaction.py @@ -0,0 +1,132 @@ +""" +File: test_discord_add_transaction.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import unittest +from discord_BaseCase import discord_BaseCase +from datetime import datetime + + +class TestAddUserRecord(discord_BaseCase): + """ + Tests the addUserrecord method + """ + + def validate_user_list(self, users) -> str: + """ + Helper method to validate the user list matches with no.of transactions + :param users: a sample dictionary of user: [records] + :type: dict + :return: True if user list matches + :rtype: bool + """ + # assert exact number of users + expected_len = 0 + for category in users: + expected_len += len(users[category]) + if expected_len != self.user.get_number_of_transactions(): + return f'Length does not match. ' \ + f'Expected {expected_len} transactions' \ + f'Found {self.user.get_number_of_transactions()}' + for category in users: + # assert same number of records per user + if len(self.user.transactions[category]) != len(users[category]): + return f'Expected {len(users[category])} records. ' \ + f'Found {len(self.user.transactions[category])}' + + # assert the record is right + if self.user.transactions[category] != users[category]: + return f"{category} record should be: {users[category]}, " \ + f"found {self.user.transactions[category]}" + + # if everything matches + return "" + + def test_add_user_record_one(self): + """ + tests adding one record for one user + :return: + """ + assert self.user.get_number_of_transactions() == 0 + # adding one record + transaction = self.create_transaction() + date = datetime.today() + record = {"Date": date, "Value": 10.00} + transaction[self.user.spend_categories[0]].append(record) + for category in transaction: + # for each record to add + for record in transaction[category]: + self.user.add_transaction(record['Date'], category, record['Value'], 2) + # validating the list + message = self.validate_user_list(transaction) + if message != "": + assert False, message + + def test_add_user_record_multiple_record(self): + """ + tests adding multiple records for one user + :return: + """ + assert self.user.get_number_of_transactions() == 0 + # adding one record + transaction = self.create_transaction() + date = datetime.today() + records = [{"Date": date, "Value": 10.00}, {"Date": date, "Value": 15.00}] + for record in records: + transaction[self.user.spend_categories[0]].append(record) + for category in transaction: + # for each record to add + for record in transaction[category]: + self.user.add_transaction(record['Date'], category, record['Value'], 1) + # validating the list + message = self.validate_user_list(transaction) + if message != "": + assert False, message + + def test_add_multiple_cat(self): + """ + tests adding multiple records for multiple users + :return: + """ + + assert self.user.get_number_of_transactions() == 0 + # adding one record + transaction = self.create_transaction() + date = datetime.today() + transaction[self.user.spend_categories[0]].append({"Date": date, "Value": 10.00}) + transaction[self.user.spend_categories[1]].append({"Date": date, "Value": 150.00}) + for category in transaction: + # for each record to add + for record in transaction[category]: + self.user.add_transaction(record['Date'], category, record['Value'], 1) + # validating the list + message = self.validate_user_list(transaction) + if message != "": + assert False, message + + +if __name__ == '__main__': + unittest.main() diff --git a/test/unit/test_discord_delete.py b/test/unit/test_discord_delete.py new file mode 100644 index 000000000..9944bdf4d --- /dev/null +++ b/test/unit/test_discord_delete.py @@ -0,0 +1,111 @@ +""" +File: test_discord_delete.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +from datetime import datetime +from discord_BaseCase import discord_BaseCase + + +class TestDeleteHistory(discord_BaseCase): + """ + Unit test for deleteHistory + """ + + def test_delete_history_none(self): + """ + Given no transactions, the list should not change + """ + # given no history + assert self.user.get_number_of_transactions() == 0 + # doing deleteHistory + self.user.deleteHistory() + # should not do anything + assert self.user.get_number_of_transactions() == 0 + + def test_delete(self): + """ + Given there is one user + deleting a transaction + should remove it + """ + # given adding one user + date = datetime.today() + transaction = self.create_transaction() + record = {"Date": date, "Value": 10.00} + transaction[self.user.spend_categories[0]].append(record) + self.user.transactions[self.user.spend_categories[0]].append(record) + # delete the transaction + self.user.deleteHistory(transaction) + assert self.user.get_number_of_transactions() == 0 + assert self.user.transactions[self.user.spend_categories[0]] == [] + + def test_delete_multiple(self): + """ + Given there is multiple transactions + deleting one should work + """ + # given adding one user + date = datetime.today() + transaction = self.create_transaction() + record = {"Date": date, "Value": 10.00} + # appending the transaction + self.user.transactions[self.user.spend_categories[0]].append(record) + # creating a record to delete + to_delete = {"Date": date, "Value": 15.00} + transaction[self.user.spend_categories[0]].append(to_delete) + self.user.transactions[self.user.spend_categories[0]].append(to_delete) + # delete the transaction + self.user.deleteHistory(transaction) + assert self.user.get_number_of_transactions() == 1 + assert self.user.transactions[self.user.spend_categories[0]] == [record] + + def test_delete_multiple_record(self): + """ + Given there is one user + deleting one record from the user + should remove it from the user list + """ + # given adding one user + date = datetime.today() + transaction = self.create_transaction() + record = {"Date": date, "Value": 10.00} + # appending the transaction + self.user.transactions[self.user.spend_categories[0]].append(record) + # creating a record to delete + to_delete = {"Date": date, "Value": 15.00} + transaction[self.user.spend_categories[0]].append(to_delete) + self.user.transactions[self.user.spend_categories[0]].append(to_delete) + # delete the transaction + self.user.deleteHistory(transaction) + assert self.user.get_number_of_transactions() == 1 + assert self.user.transactions[self.user.spend_categories[0]] == [record] + + # delete the last record + transaction = self.create_transaction() + transaction[self.user.spend_categories[0]].append(record) + self.user.deleteHistory(transaction) + assert self.user.get_number_of_transactions() == 0 + assert self.user.transactions[self.user.spend_categories[0]] == [] diff --git a/test/unit/test_discord_display_transaction.py b/test/unit/test_discord_display_transaction.py new file mode 100644 index 000000000..c8873ad1b --- /dev/null +++ b/test/unit/test_discord_display_transaction.py @@ -0,0 +1,83 @@ +""" +File: test_discord_display_transaction.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +from discord_BaseCase import discord_BaseCase +from datetime import datetime + + +class TestDisplayTransaction(discord_BaseCase): + """ + Unit test for display_transaction + """ + + def test_display_one_cat(self): + """ + Given one category, we expect one row + """ + # only 1 row + date = datetime.today() + transaction = {self.user.spend_categories[0]: [{"Date": date, "Value": 10.0}]} + expected_str = f'{self.user.spend_categories[0]}, {date.date()}, 10.0\n' + assert self.user.display_transaction(transaction) == expected_str + + def test_display_two_cat(self): + """ + Given multiple categories, it should have the + categories on separate lines + """ + # 2 rows + date = datetime.today() + transaction = {self.user.spend_categories[0]: [{"Date": date, "Value": 10.0}], + self.user.spend_categories[1]: [{"Date": date, "Value": 15.0}]} + expected_str = f'{self.user.spend_categories[0]}, {date.date()}, 10.0\n' \ + f'{self.user.spend_categories[1]}, {date.date()}, 15.0\n' + assert self.user.display_transaction(transaction) == expected_str + + def test_display_multiple_row(self): + """ + Given multiple purchases in same category + """ + date = datetime.today() + transaction = {self.user.spend_categories[0]: [{"Date": date, "Value": 10.0}, + {"Date": date, "Value": 15.0}]} + expected_str = f'{self.user.spend_categories[0]}, {date.date()}, 10.0\n' \ + f'{self.user.spend_categories[0]}, {date.date()}, 15.0\n' + assert self.user.display_transaction(transaction) == expected_str + + def test_display_spending_multiple_all(self): + """ + Given multiple categories with multiple spending's + """ + date = datetime.today() + transaction = {self.user.spend_categories[0]: [{"Date": date, "Value": 10.0}, + {"Date": date, "Value": 15.0}], + self.user.spend_categories[1]: [{"Date": date, "Value": 5}]} + expected_str = f'{self.user.spend_categories[0]}, {date.date()}, 10.0\n' \ + f'{self.user.spend_categories[0]}, {date.date()}, 15.0\n' \ + f'{self.user.spend_categories[1]}, {date.date()}, 5\n' + ret = self.user.display_transaction(transaction) + assert ret == expected_str diff --git a/test/unit/test_discord_edit.py b/test/unit/test_discord_edit.py new file mode 100644 index 000000000..4ebc2a0d4 --- /dev/null +++ b/test/unit/test_discord_edit.py @@ -0,0 +1,90 @@ +""" +File: test_discord_edit.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" +from discord_BaseCase import discord_BaseCase +from datetime import datetime, timedelta + + +class TestAddUserRecord(discord_BaseCase): + """ + Tests the edit series of functions in bot.py + """ + + def test_store_edit_transaction(self): + """ + After user enters existing transaction and data is parsed from input + user.edit_transaction should be that transaction + user.edit_category should be the category of that transaction + """ + # User enters the following date,category, value + user_date = datetime.today() + user_category = "Food" + user_value = 10.00 + userid = "2" + self.user.add_transaction(user_date, user_category, user_value, userid) + transaction = {"Date": user_date, "Value": user_value} + self.user.store_edit_transaction(transaction, user_category) + assert transaction == self.user.edit_transactions + assert user_category == self.user.edit_category + + def test_edit_date(self): + # User enters the following date,category, value + user_date = datetime.today() + edit_date = datetime.today() - timedelta(days=1) + user_category = "Groceries" + user_value = 10.00 + userid = "2" + self.user.add_transaction(user_date, user_category, user_value, userid) + transaction = {"Date": user_date, "Value": user_value} + self.user.store_edit_transaction(transaction, user_category) + self.user.edit_transaction_date(edit_date) + assert self.user.transactions["Groceries"][0]["Date"].date() == edit_date.date() + + def test_edit_transaction_category(self): + # User enters the following date,category, value + user_date = datetime.today() + user_category = "Utilities" + edit_category = "Transport" + user_value = 10.00 + userid = "2" + self.user.add_transaction(user_date, user_category, user_value, userid) + transaction = {"Date": user_date, "Value": user_value} + self.user.store_edit_transaction(transaction, user_category) + self.user.edit_transaction_category(edit_category) + assert self.user.transactions[edit_category][0] == transaction + + def test_edit_transaction_value(self): + # User enters the following date,category, value + user_date = datetime.today() + user_category = "Shopping" + user_value = 10.00 + edit_value = 20.00 + userid = "2" + self.user.add_transaction(user_date, user_category, user_value, userid) + transaction = {"Date": user_date, "Value": user_value} + self.user.store_edit_transaction(transaction, user_category) + self.user.edit_transaction_value(edit_value) + assert self.user.transactions["Shopping"][0]["Value"] == edit_value diff --git a/test/unit/test_discord_get_recordsByDate.py b/test/unit/test_discord_get_recordsByDate.py new file mode 100644 index 000000000..4875805f2 --- /dev/null +++ b/test/unit/test_discord_get_recordsByDate.py @@ -0,0 +1,120 @@ +""" +File: test_discord_get_recordsByData.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +from datetime import datetime + +from discord_BaseCase import discord_BaseCase + + +class TestGetRecordsByDate(discord_BaseCase): + """ + Unit test for deleteHistory + def get_records_by_date(date, chat_id, is_month): + + By this method, tests have been completed that the user is present + Thus, there are no tests for user not present + """ + + def add_expected(self): + + self.oct_01 = {"Date": datetime(month=10, day=1, year=2021), "Value": 10.00} + self.oct_10 = {"Date": datetime(month=10, day=10, year=2021), "Value": 15.00} + self.nov_01 = {"Date": datetime(month=11, day=1, year=2021), "Value": 5.00} + self.add_record(self.user.spend_categories[0], self.oct_01) + self.add_record(self.user.spend_categories[0], self.oct_10) + self.add_record(self.user.spend_categories[0], self.nov_01) + + def test_user_date_not_present(self): + """ + Given there is one user + calling get_records_by_date with a non-present date + should return [] + """ + self.add_expected() + wrong_date = datetime.now() + # make the date year 1, month 1, day 1 + wrong_date = wrong_date.replace(1, 1, 1) + # given the user_list + self.user.transactions = self.expected_list + user_history = self.user.get_records_by_date(wrong_date, False) + # there should be no records + assert user_history == self.create_transaction() + user_history = self.user.get_records_by_date(wrong_date, True) + # there should be no records + assert user_history == self.create_transaction() + + def test_get_by_month(self): + """ + Given there is one user + calling get_records_by_date by month + """ + self.add_expected() + # given the user_list + self.user.transactions = self.expected_list + + october = datetime.now() + # make the date match october 2021 + october = october.replace(year=2021, month=10).date() + user_history = self.user.get_records_by_date(october, True) + # the records should match october 2021 + expected_transactions = self.create_transaction() + # filter everything that is Oct-2021 + expected_transactions[self.user.spend_categories[0]] = [self.oct_01, self.oct_10] + assert user_history == expected_transactions + + def test_get_by_day(self): + """ + Given there is one user + calling get_records_by_date with a valid date + """ + + self.add_expected() + # given the user_list + self.user.transactions = self.expected_list + + october = datetime.now() + # make the date match october 2021 + october = october.replace(year=2021, month=10, day=1).date() + user_history = self.user.get_records_by_date(october, False) + # the records should match october 2021 + expected_transactions = self.create_transaction() + # filter everything that is Oct-2021 + expected_transactions[self.user.spend_categories[0]] = [self.oct_01] + assert user_history == expected_transactions + + def test_get_by_all(self): + """ + Given there is one user + calling all + """ + self.add_expected() + # given the user_list + self.user.transactions = self.expected_list + + user_history = self.user.get_records_by_date("all", True) + # there should all + assert user_history == self.expected_list diff --git a/test/unit/test_discord_monthly_budget.py b/test/unit/test_discord_monthly_budget.py new file mode 100644 index 000000000..fe6a485a1 --- /dev/null +++ b/test/unit/test_discord_monthly_budget.py @@ -0,0 +1,50 @@ +""" +File: test_discord_monthly_budget.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +from discord_BaseCase import discord_BaseCase + +class TestAddMonthlyBudget(discord_BaseCase): + def test_add_monthly_budget_valid(self): + """ + Asserts when add_monthly_budget is given a float value + """ + assert self.user.monthly_budget == 0 + amount = 10.00 + self.user.add_monthly_budget(amount, 2) + assert self.user.monthly_budget == amount + + def test_add_monthly_budget_invalid(self): + """ + Asserts when add_monthly_budget is given 0 + """ + assert self.user.monthly_budget == 0 + amount_valid = 10.00 + self.user.add_monthly_budget(amount_valid, 2) + assert self.user.monthly_budget == amount_valid + amount = 0.00 + self.user.add_monthly_budget(amount, 2) + assert self.user.monthly_budget == amount_valid diff --git a/test/unit/test_discord_monthly_total.py b/test/unit/test_discord_monthly_total.py new file mode 100644 index 000000000..643b9e930 --- /dev/null +++ b/test/unit/test_discord_monthly_total.py @@ -0,0 +1,88 @@ +""" +File: test_discord_monthly_total.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +from discord_BaseCase import discord_BaseCase +from datetime import datetime + +class TestMonthlyTotal(discord_BaseCase): + """ + Unit test for monthly total + """ + def test_one_transaction(self): + """ + Given one transaction, we expect total to be the value of that transaction + """ + date = datetime.today() + value = 12.00 + transaction = self.create_transaction() + date = datetime.today() + record = {"Date": date, "Value": value} + transaction[self.user.spend_categories[0]].append(record) + for category in transaction: + # for each record to add + for record in transaction[category]: + self.user.add_transaction(record['Date'], category, record['Value'], 2) + assert self.user.monthly_total() == value + + def test_multiple_transaction_same_cat(self): + """ + Given multiple transactions of same category, we expect total to be the sum of all the transactions + """ + date = datetime.today() + value = [12.00, 11.00] + transaction = self.create_transaction() + date = datetime.today() + records = [{"Date": date, "Value": value[0]}, {"Date": date, "Value": value[1]}] + for record in records: + transaction[self.user.spend_categories[0]].append(record) + for category in transaction: + # for each record to add + for record in transaction[category]: + self.user.add_transaction(record['Date'], category, record['Value'], 2) + assert self.user.monthly_total() == sum(value) + + def test_multiple_transaction_multiple_cat(self): + """ + Given multiple transactions of different categories, we expect total to be the sum of all the transactions + """ + date = datetime.today() + value = [12.00, 11.00, 21.50, 14.25] + transaction = self.create_transaction() + date = datetime.today() + transaction[self.user.spend_categories[0]].append({"Date": date, "Value": value[0]}) + transaction[self.user.spend_categories[0]].append({"Date": date, "Value": value[1]}) + transaction[self.user.spend_categories[1]].append({"Date": date, "Value": value[2]}) + transaction[self.user.spend_categories[1]].append({"Date": date, "Value": value[3]}) + for category in transaction: + # for each record to add + for record in transaction[category]: + self.user.add_transaction(record['Date'], category, record['Value'], 2) + assert self.user.monthly_total() == sum(value) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/unit/test_discord_save_user.py b/test/unit/test_discord_save_user.py new file mode 100644 index 000000000..77b3cbab9 --- /dev/null +++ b/test/unit/test_discord_save_user.py @@ -0,0 +1,96 @@ +""" +File: test_discord_save_user.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" +import os +import pathlib +import pickle + +from discord_BaseCase import discord_BaseCase + + +def users_equal(user_1, user_2): + if user_1.spend_categories != user_2.spend_categories: + return "Spend Categories do not match" + if user_1.spend_display_option != user_2.spend_display_option: + return "spend_display_option do not match" + if user_1.transactions != user_2.transactions: + return "transactions do not match" + if user_1.edit_transactions != user_2.edit_transactions: + return "edit_transactions do not match" + if user_1.edit_category != user_2.edit_category: + return "edit_category do not match" + if user_1.monthly_budget != user_2.monthly_budget: + return "monthly_budget do not match" + return True + + +class TestSaveUser(discord_BaseCase): + """ + Unit test for save_user + """ + + def test_save_no_history(self): + """ + given a valid user, saving and loading should return the same user + """ + prev_user = self.user + # with no history, call save_user + self.user.save_user(2) + # assert the pickle exists + abspath = pathlib.Path("discordData/2.pickle").absolute() + assert os.path.exists(abspath) + + with open(abspath, "rb") as f: + new_user = pickle.load(f) + # assert they are equal + assert new_user is not None + are_equal = users_equal(prev_user, new_user) + if not are_equal: + assert False, are_equal + + def test_valid_history(self): + """ + given a valid user, saving should yield the same user + """ + self.user.spend_categories.append("TEST") + self.user.spend_display_option.append("otherTest") + self.user.transactions[self.user.spend_categories[0]].append({"TEST": 0}) + self.user.edit_transactions["TEST"] = 0 + self.user.edit_category["TEST"] = 2 + self.user.monthly_budget = 100 + prev_user = self.user + # with history, call save_user + self.user.save_user(2) + # assert the pickle exists + abspath = pathlib.Path("discordData/2.pickle").absolute() + assert os.path.exists(abspath) + with open(abspath, "rb") as f: + new_user = pickle.load(f) + # assert they are equal + assert new_user is not None + are_equal = users_equal(prev_user, new_user) + if not are_equal: + assert False, are_equal diff --git a/test/unit/test_discord_validations.py b/test/unit/test_discord_validations.py new file mode 100644 index 000000000..bc0711d21 --- /dev/null +++ b/test/unit/test_discord_validations.py @@ -0,0 +1,114 @@ +""" +File: test_discord_validations.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +from discord_BaseCase import discord_BaseCase +from datetime import datetime + + +class TestValidateEnteredAmount(discord_BaseCase): + """ + Unit test for get user history + """ + + def test_validate_entered_amount_empty(self): + """ + Asserts when validate_entered_amount is given an empty string, + 0 is returned + + """ + # given an empty string for amount entered, 0 should be returned + assert self.user.validate_entered_amount("") == 0 + + def test_validate_entered_amount_string(self): + """ + Asserts when validate_entered_amount is given a string + 0 is returned + """ + # given an string, 0 should be returned + assert self.user.validate_entered_amount("Test") == 0 + # given a string that contains numbers and a string + assert self.user.validate_entered_amount("000t") == 0 + + def test_validate_entered_amount_nan(self): + """ + Asserts when validate_entered_amount is given an invalid + number, 0 is returned + """ + # given a negative number + assert self.user.validate_entered_amount("-1") == 0 + # given 0 + assert self.user.validate_entered_amount("0") == 0 + # given a number with dollar sign + assert self.user.validate_entered_amount("$10") == 0 + # given a number with 2 decimals + assert self.user.validate_entered_amount("10..0") == 0 + + def test_validate_entered_amount_valid(self): + """ + Asserts when validate_entered_amount is given an valid + number, the number is returned + """ + # given a positive number + assert self.user.validate_entered_amount("1") == 1.00 + # given a positive number with decimals + assert self.user.validate_entered_amount("10.10") == 10.10 + # given a number with 14 digits + assert self.user.validate_entered_amount("1000000000.00") == 1000000000.00 + + def test_valid_date(self): + """ + Given no transactions, the list should not change + """ + date = datetime.today() + # format it as a year + dateFormat = '%d-%b-%Y' + monthFormat = '%b-%Y' + validated_d_m_y = self.user.validate_date_format(date.strftime(dateFormat), dateFormat) + assert validated_d_m_y.month == date.month + assert validated_d_m_y.day == date.day + assert validated_d_m_y.year == date.year + validated_m_y = self.user.validate_date_format(date.strftime(monthFormat), monthFormat) + assert validated_m_y.month == date.month + assert validated_m_y.year == date.year + + def test_invalid(self): + """ + Given there is one user + deleting a transaction + should remove it + """ + date = datetime.today() + # invalid formats + dateFormat = 'random' + error = self.user.validate_date_format(date.strftime('%d-%b-%Y'), dateFormat) + assert error is None + # mismatched formats + dateFormat = '%d-%b-%Y' + monthFormat = '%b-%Y' + validated_m_y = self.user.validate_date_format(date.strftime(dateFormat), monthFormat) + assert validated_m_y is None + diff --git a/test/bot/test_display.py b/test/unit/test_display.py similarity index 71% rename from test/bot/test_display.py rename to test/unit/test_display.py index 77472709f..fd70299a8 100644 --- a/test/bot/test_display.py +++ b/test/unit/test_display.py @@ -1,5 +1,28 @@ """ -Tests display command +File: test_display.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ import time import unittest @@ -89,4 +112,4 @@ def test_display_command_records(self): if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/unit/test_display_transaction.py b/test/unit/test_display_transaction.py index 8db53c22d..59c3bc1f6 100644 --- a/test/unit/test_display_transaction.py +++ b/test/unit/test_display_transaction.py @@ -1,3 +1,30 @@ +""" +File: test_display_transactions.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + from BaseCase import BaseCase from datetime import datetime diff --git a/test/bot/test_edit.py b/test/unit/test_edit.py similarity index 65% rename from test/bot/test_edit.py rename to test/unit/test_edit.py index 16cf2aa4a..b74ac159a 100644 --- a/test/bot/test_edit.py +++ b/test/unit/test_edit.py @@ -1,6 +1,30 @@ """ -Tests edit command +File: test_edit.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ + import time import unittest from bot_utils import BotTest @@ -68,4 +92,4 @@ def test_edit_command_records(self): if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/unit/test_edit_functions.py b/test/unit/test_edit_functions.py index 1aca1be53..e34d885a6 100644 --- a/test/unit/test_edit_functions.py +++ b/test/unit/test_edit_functions.py @@ -1,4 +1,29 @@ -import unittest +""" +File: test_edit_functions.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" from BaseCase import BaseCase from datetime import datetime, timedelta @@ -18,7 +43,7 @@ def test_store_edit_transaction(self): user_date = datetime.today() user_category = "Food" user_value = 10.00 - userid = "33" + userid = "1" self.user.add_transaction(user_date, user_category, user_value, userid) transaction = {"Date": user_date, "Value": user_value} self.user.store_edit_transaction(transaction, user_category) @@ -31,7 +56,7 @@ def test_edit_date(self): edit_date = datetime.today() - timedelta(days=1) user_category = "Groceries" user_value = 10.00 - userid = "33" + userid = "1" self.user.add_transaction(user_date, user_category, user_value, userid) transaction = {"Date": user_date, "Value": user_value} self.user.store_edit_transaction(transaction, user_category) @@ -44,7 +69,7 @@ def test_edit_transaction_category(self): user_category = "Utilities" edit_category = "Transport" user_value = 10.00 - userid = "33" + userid = "1" self.user.add_transaction(user_date, user_category, user_value, userid) transaction = {"Date": user_date, "Value": user_value} self.user.store_edit_transaction(transaction, user_category) @@ -57,7 +82,7 @@ def test_edit_transaction_value(self): user_category = "Shopping" user_value = 10.00 edit_value = 20.00 - userid = "33" + userid = "1" self.user.add_transaction(user_date, user_category, user_value, userid) transaction = {"Date": user_date, "Value": user_value} self.user.store_edit_transaction(transaction, user_category) diff --git a/test/unit/test_get_number_of_transactions.py b/test/unit/test_get_number_of_transactions.py index b17b6da19..8c65be4ba 100644 --- a/test/unit/test_get_number_of_transactions.py +++ b/test/unit/test_get_number_of_transactions.py @@ -1,3 +1,30 @@ +""" +File: test_get_number_of_transactions.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + from BaseCase import BaseCase from datetime import datetime diff --git a/test/unit/test_get_records_by_date.py b/test/unit/test_get_records_by_date.py index 3587c3232..2100b1ca3 100644 --- a/test/unit/test_get_records_by_date.py +++ b/test/unit/test_get_records_by_date.py @@ -1,5 +1,28 @@ """ -Test for the getRecordsByDate function +File: test_get_records_by_date.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ from datetime import datetime diff --git a/test/bot/test_history.py b/test/unit/test_history.py similarity index 55% rename from test/bot/test_history.py rename to test/unit/test_history.py index 6a52a13cc..11eb48dc7 100644 --- a/test/bot/test_history.py +++ b/test/unit/test_history.py @@ -1,5 +1,28 @@ """ -Tests history command +File: test_history.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ import time import unittest @@ -50,4 +73,4 @@ def test_history_command_records(self): if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/unit/test_monthly_total.py b/test/unit/test_monthly_total.py index 9cd02fdc6..4104510bf 100644 --- a/test/unit/test_monthly_total.py +++ b/test/unit/test_monthly_total.py @@ -1,7 +1,29 @@ """ -Tests the monthly_total_method -""" +File: test_monthly_total.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" from BaseCase import BaseCase from datetime import datetime diff --git a/test/unit/test_save_user.py b/test/unit/test_save_user.py index 162fb16d4..9cbd5021f 100644 --- a/test/unit/test_save_user.py +++ b/test/unit/test_save_user.py @@ -1,5 +1,28 @@ """ -Test for the save_user method +File: test_save_user.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ import os import pathlib @@ -37,7 +60,7 @@ def test_save_no_history(self): # with no history, call save_user self.user.save_user(1) # assert the pickle exists - abspath = pathlib.Path("data/1.pickle").absolute() + abspath = pathlib.Path("teleData/1.pickle").absolute() assert os.path.exists(abspath) with open(abspath, "rb") as f: @@ -62,7 +85,7 @@ def test_valid_history(self): # with history, call save_user self.user.save_user(1) # assert the pickle exists - abspath = pathlib.Path("data/1.pickle").absolute() + abspath = pathlib.Path("teleData/1.pickle").absolute() assert os.path.exists(abspath) with open(abspath, "rb") as f: new_user = pickle.load(f) diff --git a/test/bot/test_start_and_menu.py b/test/unit/test_start_and_menu.py similarity index 54% rename from test/bot/test_start_and_menu.py rename to test/unit/test_start_and_menu.py index 5618fd48e..e45d74db7 100644 --- a/test/bot/test_start_and_menu.py +++ b/test/unit/test_start_and_menu.py @@ -1,5 +1,28 @@ """ -Tests start and menu commands +File: test_start_and_menu.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ import time import unittest @@ -46,4 +69,4 @@ def test_menu_command(self): if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/test/unit/test_validate_date_format.py b/test/unit/test_validate_date_format.py index c91677f46..e698b3b3b 100644 --- a/test/unit/test_validate_date_format.py +++ b/test/unit/test_validate_date_format.py @@ -1,5 +1,28 @@ """ -Test for the deleteHistory function +File: test_validate_date_formate.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ from datetime import datetime diff --git a/test/unit/test_validate_entered_amount.py b/test/unit/test_validate_entered_amount.py index 7d6d9ef44..3d2ca4ff5 100644 --- a/test/unit/test_validate_entered_amount.py +++ b/test/unit/test_validate_entered_amount.py @@ -1,7 +1,28 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ -Tests the validate_entered_amount method +File: test_validate_entered_amount.py +Author: Vyshnavi Adusumelli, Tejaswini Panati, Harshavardhan Bandaru +Date: October 01, 2023 +Description: File contains Test cases. + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. """ from BaseCase import BaseCase