diff options
Diffstat (limited to 'ihatemoney/tests')
| -rw-r--r-- | ihatemoney/tests/tests.py | 1600 |
1 files changed, 921 insertions, 679 deletions
diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index 3ff8a72..1767475 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -16,13 +16,12 @@ from flask import session from flask_testing import TestCase from ihatemoney.run import create_app, db, load_configuration -from ihatemoney.manage import ( - GenerateConfig, GeneratePasswordHash, DeleteProject) +from ihatemoney.manage import GenerateConfig, GeneratePasswordHash, DeleteProject from ihatemoney import models from ihatemoney import utils # Unset configuration file env var if previously set -os.environ.pop('IHATEMONEY_SETTINGS_FILE_PATH', None) +os.environ.pop("IHATEMONEY_SETTINGS_FILE_PATH", None) __HERE__ = os.path.dirname(os.path.abspath(__file__)) @@ -46,25 +45,32 @@ class BaseTestCase(TestCase): def login(self, project, password=None, test_client=None): password = password or project - return self.client.post('/authenticate', data=dict( - id=project, password=password), follow_redirects=True) + return self.client.post( + "/authenticate", + data=dict(id=project, password=password), + follow_redirects=True, + ) def post_project(self, name): """Create a fake project""" # create the project - self.client.post("/create", data={ - 'name': name, - 'id': name, - 'password': name, - 'contact_email': '%s@notmyidea.org' % name - }) + self.client.post( + "/create", + data={ + "name": name, + "id": name, + "password": name, + "contact_email": "%s@notmyidea.org" % name, + }, + ) def create_project(self, name): project = models.Project( id=name, name=str(name), password=generate_password_hash(name), - contact_email="%s@notmyidea.org" % name) + contact_email="%s@notmyidea.org" % name, + ) models.db.session.add(project) models.db.session.commit() @@ -75,46 +81,53 @@ class IhatemoneyTestCase(BaseTestCase): WTF_CSRF_ENABLED = False # Simplifies the tests. def assertStatus(self, expected, resp, url=""): - return self.assertEqual(expected, resp.status_code, - "%s expected %s, got %s" % (url, expected, resp.status_code)) + return self.assertEqual( + expected, + resp.status_code, + "%s expected %s, got %s" % (url, expected, resp.status_code), + ) class ConfigurationTestCase(BaseTestCase): - def test_default_configuration(self): """Test that default settings are loaded when no other configuration file is specified""" - self.assertFalse(self.app.config['DEBUG']) - self.assertEqual(self.app.config['SQLALCHEMY_DATABASE_URI'], 'sqlite:////tmp/ihatemoney.db') - self.assertFalse(self.app.config['SQLALCHEMY_TRACK_MODIFICATIONS']) - self.assertEqual(self.app.config['MAIL_DEFAULT_SENDER'], - ("Budget manager", "budget@notmyidea.org")) + self.assertFalse(self.app.config["DEBUG"]) + self.assertEqual( + self.app.config["SQLALCHEMY_DATABASE_URI"], "sqlite:////tmp/ihatemoney.db" + ) + self.assertFalse(self.app.config["SQLALCHEMY_TRACK_MODIFICATIONS"]) + self.assertEqual( + self.app.config["MAIL_DEFAULT_SENDER"], + ("Budget manager", "budget@notmyidea.org"), + ) def test_env_var_configuration_file(self): """Test that settings are loaded from the specified configuration file""" - os.environ['IHATEMONEY_SETTINGS_FILE_PATH'] = os.path.join(__HERE__, - "ihatemoney_envvar.cfg") + os.environ["IHATEMONEY_SETTINGS_FILE_PATH"] = os.path.join( + __HERE__, "ihatemoney_envvar.cfg" + ) load_configuration(self.app) - self.assertEqual(self.app.config['SECRET_KEY'], 'lalatra') + self.assertEqual(self.app.config["SECRET_KEY"], "lalatra") # Test that the specified configuration file is loaded # even if the default configuration file ihatemoney.cfg exists - os.environ['IHATEMONEY_SETTINGS_FILE_PATH'] = os.path.join(__HERE__, - "ihatemoney_envvar.cfg") + os.environ["IHATEMONEY_SETTINGS_FILE_PATH"] = os.path.join( + __HERE__, "ihatemoney_envvar.cfg" + ) self.app.config.root_path = __HERE__ load_configuration(self.app) - self.assertEqual(self.app.config['SECRET_KEY'], 'lalatra') + self.assertEqual(self.app.config["SECRET_KEY"], "lalatra") - os.environ.pop('IHATEMONEY_SETTINGS_FILE_PATH', None) + os.environ.pop("IHATEMONEY_SETTINGS_FILE_PATH", None) def test_default_configuration_file(self): """Test that settings are loaded from the default configuration file""" self.app.config.root_path = __HERE__ load_configuration(self.app) - self.assertEqual(self.app.config['SECRET_KEY'], 'supersecret') + self.assertEqual(self.app.config["SECRET_KEY"], "supersecret") class BudgetTestCase(IhatemoneyTestCase): - def test_notifications(self): """Test that the notifications are sent, and that email adresses are checked properly. @@ -126,8 +139,9 @@ class BudgetTestCase(IhatemoneyTestCase): self.login("raclette") self.post_project("raclette") - self.client.post("/raclette/invite", - data={"emails": 'alexis@notmyidea.org'}) + self.client.post( + "/raclette/invite", data={"emails": "alexis@notmyidea.org"} + ) self.assertEqual(len(outbox), 2) self.assertEqual(outbox[0].recipients, ["raclette@notmyidea.org"]) @@ -135,25 +149,28 @@ class BudgetTestCase(IhatemoneyTestCase): # sending a message to multiple persons with self.app.mail.record_messages() as outbox: - self.client.post("/raclette/invite", - data={"emails": 'alexis@notmyidea.org, toto@notmyidea.org'}) + self.client.post( + "/raclette/invite", + data={"emails": "alexis@notmyidea.org, toto@notmyidea.org"}, + ) # only one message is sent to multiple persons self.assertEqual(len(outbox), 1) - self.assertEqual(outbox[0].recipients, - ["alexis@notmyidea.org", "toto@notmyidea.org"]) + self.assertEqual( + outbox[0].recipients, ["alexis@notmyidea.org", "toto@notmyidea.org"] + ) # mail address checking with self.app.mail.record_messages() as outbox: - response = self.client.post("/raclette/invite", - data={"emails": "toto"}) + response = self.client.post("/raclette/invite", data={"emails": "toto"}) self.assertEqual(len(outbox), 0) # no message sent - self.assertIn("The email toto is not valid", response.data.decode('utf-8')) + self.assertIn("The email toto is not valid", response.data.decode("utf-8")) # mixing good and wrong adresses shouldn't send any messages with self.app.mail.record_messages() as outbox: - self.client.post("/raclette/invite", - data={"emails": 'alexis@notmyidea.org, alexis'}) # not valid + self.client.post( + "/raclette/invite", data={"emails": "alexis@notmyidea.org, alexis"} + ) # not valid # only one message is sent to multiple persons self.assertEqual(len(outbox), 0) @@ -164,25 +181,24 @@ class BudgetTestCase(IhatemoneyTestCase): self.login("raclette") self.post_project("raclette") with self.app.mail.record_messages() as outbox: - self.client.post("/raclette/invite", - data={"emails": 'toto@notmyidea.org'}) + self.client.post("/raclette/invite", data={"emails": "toto@notmyidea.org"}) self.assertEqual(len(outbox), 1) - url_start = outbox[0].body.find('You can log in using this link: ') + 32 - url_end = outbox[0].body.find('.\n', url_start) + url_start = outbox[0].body.find("You can log in using this link: ") + 32 + url_end = outbox[0].body.find(".\n", url_start) url = outbox[0].body[url_start:url_end] self.client.get("/exit") # Test that we got a valid token resp = self.client.get(url, follow_redirects=True) self.assertIn( 'You probably want to <a href="/raclette/members/add"', - resp.data.decode('utf-8') + resp.data.decode("utf-8"), ) # Test empty and invalid tokens self.client.get("/exit") resp = self.client.get("/authenticate") - self.assertIn("You either provided a bad token", resp.data.decode('utf-8')) + self.assertIn("You either provided a bad token", resp.data.decode("utf-8")) resp = self.client.get("/authenticate?token=token") - self.assertIn("You either provided a bad token", resp.data.decode('utf-8')) + self.assertIn("You either provided a bad token", resp.data.decode("utf-8")) def test_password_reminder(self): # test that it is possible to have an email cotaining the password of a @@ -209,48 +225,58 @@ class BudgetTestCase(IhatemoneyTestCase): with self.app.mail.record_messages() as outbox: self.client.post("/password-reminder", data={"id": "raclette"}) self.assertEqual(len(outbox), 1) - url_start = outbox[0].body.find('You can reset it here: ') + 23 - url_end = outbox[0].body.find('.\n', url_start) + url_start = outbox[0].body.find("You can reset it here: ") + 23 + url_end = outbox[0].body.find(".\n", url_start) url = outbox[0].body[url_start:url_end] # Test that we got a valid token resp = self.client.get(url) - self.assertIn("Password confirmation</label>", resp.data.decode('utf-8')) + self.assertIn("Password confirmation</label>", resp.data.decode("utf-8")) # Test that password can be changed - self.client.post(url, data={'password': 'pass', 'password_confirmation': 'pass'}) - resp = self.login('raclette', password='pass') - self.assertIn("<title>Account manager - raclette</title>", resp.data.decode('utf-8')) + self.client.post( + url, data={"password": "pass", "password_confirmation": "pass"} + ) + resp = self.login("raclette", password="pass") + self.assertIn( + "<title>Account manager - raclette</title>", resp.data.decode("utf-8") + ) # Test empty and null tokens resp = self.client.get("/reset-password") - self.assertIn("No token provided", resp.data.decode('utf-8')) + self.assertIn("No token provided", resp.data.decode("utf-8")) resp = self.client.get("/reset-password?token=token") - self.assertIn("Invalid token", resp.data.decode('utf-8')) + self.assertIn("Invalid token", resp.data.decode("utf-8")) def test_project_creation(self): with self.app.test_client() as c: # add a valid project - c.post("/create", data={ - 'name': 'The fabulous raclette party', - 'id': 'raclette', - 'password': 'party', - 'contact_email': 'raclette@notmyidea.org' - }) + c.post( + "/create", + data={ + "name": "The fabulous raclette party", + "id": "raclette", + "password": "party", + "contact_email": "raclette@notmyidea.org", + }, + ) # session is updated - self.assertTrue(session['raclette']) + self.assertTrue(session["raclette"]) # project is created self.assertEqual(len(models.Project.query.all()), 1) # Add a second project with the same id - models.Project.query.get('raclette') + models.Project.query.get("raclette") - c.post("/create", data={ - 'name': 'Another raclette party', - 'id': 'raclette', # already used ! - 'password': 'party', - 'contact_email': 'raclette@notmyidea.org' - }) + c.post( + "/create", + data={ + "name": "Another raclette party", + "id": "raclette", # already used ! + "password": "party", + "contact_email": "raclette@notmyidea.org", + }, + ) # no new project added self.assertEqual(len(models.Project.query.all()), 1) @@ -258,17 +284,20 @@ class BudgetTestCase(IhatemoneyTestCase): def test_project_deletion(self): with self.app.test_client() as c: - c.post("/create", data={ - 'name': 'raclette party', - 'id': 'raclette', - 'password': 'party', - 'contact_email': 'raclette@notmyidea.org' - }) + c.post( + "/create", + data={ + "name": "raclette party", + "id": "raclette", + "password": "party", + "contact_email": "raclette@notmyidea.org", + }, + ) # project added self.assertEqual(len(models.Project.query.all()), 1) - c.get('/raclette/delete') + c.get("/raclette/delete") # project removed self.assertEqual(len(models.Project.query.all()), 0) @@ -282,18 +311,16 @@ class BudgetTestCase(IhatemoneyTestCase): # Empty bill list and no members, should now propose to add members first self.assertIn( 'You probably want to <a href="/raclette/members/add"', - result.data.decode('utf-8') + result.data.decode("utf-8"), ) - result = self.client.post("/raclette/members/add", - data={'name': 'alexis'}) + result = self.client.post("/raclette/members/add", data={"name": "alexis"}) result = self.client.get("/raclette/") # Empty bill with member, list should now propose to add bills self.assertIn( - 'You probably want to <a href="/raclette/add"', - result.data.decode('utf-8') + 'You probably want to <a href="/raclette/add"', result.data.decode("utf-8") ) def test_membership(self): @@ -301,92 +328,98 @@ class BudgetTestCase(IhatemoneyTestCase): self.login("raclette") # adds a member to this project - self.client.post("/raclette/members/add", data={'name': 'alexis'}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) self.assertEqual(len(models.Project.query.get("raclette").members), 1) # adds him twice - result = self.client.post("/raclette/members/add", - data={'name': 'alexis'}) + result = self.client.post("/raclette/members/add", data={"name": "alexis"}) # should not accept him self.assertEqual(len(models.Project.query.get("raclette").members), 1) # add fred - self.client.post("/raclette/members/add", data={'name': 'fred'}) + self.client.post("/raclette/members/add", data={"name": "fred"}) self.assertEqual(len(models.Project.query.get("raclette").members), 2) # check fred is present in the bills page result = self.client.get("/raclette/") - self.assertIn("fred", result.data.decode('utf-8')) + self.assertIn("fred", result.data.decode("utf-8")) # remove fred - self.client.post("/raclette/members/%s/delete" % - models.Project.query.get("raclette").members[-1].id) + self.client.post( + "/raclette/members/%s/delete" + % models.Project.query.get("raclette").members[-1].id + ) # as fred is not bound to any bill, he is removed self.assertEqual(len(models.Project.query.get("raclette").members), 1) # add fred again - self.client.post("/raclette/members/add", data={'name': 'fred'}) + self.client.post("/raclette/members/add", data={"name": "fred"}) fred_id = models.Project.query.get("raclette").members[-1].id # bound him to a bill - result = self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': fred_id, - 'payed_for': [fred_id, ], - 'amount': '25', - }) + result = self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": fred_id, + "payed_for": [fred_id], + "amount": "25", + }, + ) # remove fred self.client.post("/raclette/members/%s/delete" % fred_id) # he is still in the database, but is deactivated self.assertEqual(len(models.Project.query.get("raclette").members), 2) - self.assertEqual( - len(models.Project.query.get("raclette").active_members), 1) + self.assertEqual(len(models.Project.query.get("raclette").active_members), 1) # as fred is now deactivated, check that he is not listed when adding # a bill or displaying the balance result = self.client.get("/raclette/") - self.assertNotIn(("/raclette/members/%s/delete" % fred_id), result.data.decode('utf-8')) + self.assertNotIn( + ("/raclette/members/%s/delete" % fred_id), result.data.decode("utf-8") + ) result = self.client.get("/raclette/add") - self.assertNotIn("fred", result.data.decode('utf-8')) + self.assertNotIn("fred", result.data.decode("utf-8")) # adding him again should reactivate him - self.client.post("/raclette/members/add", data={'name': 'fred'}) - self.assertEqual( - len(models.Project.query.get("raclette").active_members), 2) + self.client.post("/raclette/members/add", data={"name": "fred"}) + self.assertEqual(len(models.Project.query.get("raclette").active_members), 2) # adding an user with the same name as another user from a different # project should not cause any troubles self.post_project("randomid") self.login("randomid") - self.client.post("/randomid/members/add", data={'name': 'fred'}) - self.assertEqual( - len(models.Project.query.get("randomid").active_members), 1) + self.client.post("/randomid/members/add", data={"name": "fred"}) + self.assertEqual(len(models.Project.query.get("randomid").active_members), 1) def test_person_model(self): self.post_project("raclette") self.login("raclette") # adds a member to this project - self.client.post("/raclette/members/add", data={'name': 'alexis'}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) alexis = models.Project.query.get("raclette").members[-1] # should not have any bills self.assertFalse(alexis.has_bills()) # bound him to a bill - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': alexis.id, - 'payed_for': [alexis.id, ], - 'amount': '25', - }) + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": alexis.id, + "payed_for": [alexis.id], + "amount": "25", + }, + ) # should have a bill now alexis = models.Project.query.get("raclette").members[-1] @@ -397,7 +430,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.login("raclette") # adds a member to this project - self.client.post("/raclette/members/add", data={'name': 'alexis'}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) # try to remove the member using GET method response = self.client.get("/raclette/members/1/delete") @@ -405,8 +438,7 @@ class BudgetTestCase(IhatemoneyTestCase): # delete user using POST method self.client.post("/raclette/members/1/delete") - self.assertEqual( - len(models.Project.query.get("raclette").active_members), 0) + self.assertEqual(len(models.Project.query.get("raclette").active_members), 0) # try to delete an user already deleted self.client.post("/raclette/members/1/delete") @@ -417,17 +449,17 @@ class BudgetTestCase(IhatemoneyTestCase): self.assertTrue(models.Project.query.get("demo") is not None) def test_deactivated_demo(self): - self.app.config['ACTIVATE_DEMO_PROJECT'] = False + self.app.config["ACTIVATE_DEMO_PROJECT"] = False # test redirection to the create project form when demo is deactivated resp = self.client.get("/demo") - self.assertIn('<a href="/create?project_id=demo">', resp.data.decode('utf-8')) + self.assertIn('<a href="/create?project_id=demo">', resp.data.decode("utf-8")) def test_authentication(self): # try to authenticate without credentials should redirect # to the authentication page resp = self.client.post("/authenticate") - self.assertIn("Authentication", resp.data.decode('utf-8')) + self.assertIn("Authentication", resp.data.decode("utf-8")) # raclette that the login / logout process works self.create_project("raclette") @@ -435,110 +467,128 @@ class BudgetTestCase(IhatemoneyTestCase): # try to see the project while not being authenticated should redirect # to the authentication page resp = self.client.get("/raclette", follow_redirects=True) - self.assertIn("Authentication", resp.data.decode('utf-8')) + self.assertIn("Authentication", resp.data.decode("utf-8")) # try to connect with wrong credentials should not work with self.app.test_client() as c: - resp = c.post("/authenticate", - data={'id': 'raclette', 'password': 'nope'}) + resp = c.post("/authenticate", data={"id": "raclette", "password": "nope"}) - self.assertIn("Authentication", resp.data.decode('utf-8')) - self.assertNotIn('raclette', session) + self.assertIn("Authentication", resp.data.decode("utf-8")) + self.assertNotIn("raclette", session) # try to connect with the right credentials should work with self.app.test_client() as c: - resp = c.post("/authenticate", - data={'id': 'raclette', 'password': 'raclette'}) + resp = c.post( + "/authenticate", data={"id": "raclette", "password": "raclette"} + ) - self.assertNotIn("Authentication", resp.data.decode('utf-8')) - self.assertIn('raclette', session) - self.assertTrue(session['raclette']) + self.assertNotIn("Authentication", resp.data.decode("utf-8")) + self.assertIn("raclette", session) + self.assertTrue(session["raclette"]) # logout should wipe the session out c.get("/exit") - self.assertNotIn('raclette', session) + self.assertNotIn("raclette", session) # test that with admin credentials, one can access every project - self.app.config['ADMIN_PASSWORD'] = generate_password_hash("pass") + self.app.config["ADMIN_PASSWORD"] = generate_password_hash("pass") with self.app.test_client() as c: - resp = c.post("/admin?goto=%2Fraclette", data={'admin_password': 'pass'}) - self.assertNotIn("Authentication", resp.data.decode('utf-8')) - self.assertTrue(session['is_admin']) + resp = c.post("/admin?goto=%2Fraclette", data={"admin_password": "pass"}) + self.assertNotIn("Authentication", resp.data.decode("utf-8")) + self.assertTrue(session["is_admin"]) def test_admin_authentication(self): - self.app.config['ADMIN_PASSWORD'] = generate_password_hash("pass") + self.app.config["ADMIN_PASSWORD"] = generate_password_hash("pass") # Disable public project creation so we have an admin endpoint to test - self.app.config['ALLOW_PUBLIC_PROJECT_CREATION'] = False + self.app.config["ALLOW_PUBLIC_PROJECT_CREATION"] = False # test the redirection to the authentication page when trying to access admin endpoints resp = self.client.get("/create") - self.assertIn('<a href="/admin?goto=%2Fcreate">', resp.data.decode('utf-8')) + self.assertIn('<a href="/admin?goto=%2Fcreate">', resp.data.decode("utf-8")) # test right password - resp = self.client.post("/admin?goto=%2Fcreate", data={'admin_password': 'pass'}) - self.assertIn('<a href="/create">/create</a>', resp.data.decode('utf-8')) + resp = self.client.post( + "/admin?goto=%2Fcreate", data={"admin_password": "pass"} + ) + self.assertIn('<a href="/create">/create</a>', resp.data.decode("utf-8")) # test wrong password - resp = self.client.post("/admin?goto=%2Fcreate", data={'admin_password': 'wrong'}) - self.assertNotIn('<a href="/create">/create</a>', resp.data.decode('utf-8')) + resp = self.client.post( + "/admin?goto=%2Fcreate", data={"admin_password": "wrong"} + ) + self.assertNotIn('<a href="/create">/create</a>', resp.data.decode("utf-8")) # test empty password - resp = self.client.post("/admin?goto=%2Fcreate", data={'admin_password': ''}) - self.assertNotIn('<a href="/create">/create</a>', resp.data.decode('utf-8')) + resp = self.client.post("/admin?goto=%2Fcreate", data={"admin_password": ""}) + self.assertNotIn('<a href="/create">/create</a>', resp.data.decode("utf-8")) def test_login_throttler(self): - self.app.config['ADMIN_PASSWORD'] = generate_password_hash("pass") + self.app.config["ADMIN_PASSWORD"] = generate_password_hash("pass") # Activate admin login throttling by authenticating 4 times with a wrong passsword - self.client.post("/admin?goto=%2Fcreate", data={'admin_password': 'wrong'}) - self.client.post("/admin?goto=%2Fcreate", data={'admin_password': 'wrong'}) - self.client.post("/admin?goto=%2Fcreate", data={'admin_password': 'wrong'}) - resp = self.client.post("/admin?goto=%2Fcreate", data={'admin_password': 'wrong'}) + self.client.post("/admin?goto=%2Fcreate", data={"admin_password": "wrong"}) + self.client.post("/admin?goto=%2Fcreate", data={"admin_password": "wrong"}) + self.client.post("/admin?goto=%2Fcreate", data={"admin_password": "wrong"}) + resp = self.client.post( + "/admin?goto=%2Fcreate", data={"admin_password": "wrong"} + ) - self.assertIn('Too many failed login attempts, please retry later.', - resp.data.decode('utf-8')) + self.assertIn( + "Too many failed login attempts, please retry later.", + resp.data.decode("utf-8"), + ) # Change throttling delay import gc + for obj in gc.get_objects(): if isinstance(obj, utils.LoginThrottler): obj._delay = 0.005 break # Wait for delay to expire and retry logging in sleep(1) - resp = self.client.post("/admin?goto=%2Fcreate", data={'admin_password': 'wrong'}) - self.assertNotIn('Too many failed login attempts, please retry later.', - resp.data.decode('utf-8')) + resp = self.client.post( + "/admin?goto=%2Fcreate", data={"admin_password": "wrong"} + ) + self.assertNotIn( + "Too many failed login attempts, please retry later.", + resp.data.decode("utf-8"), + ) def test_manage_bills(self): self.post_project("raclette") # add two persons - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - self.client.post("/raclette/members/add", data={'name': 'fred'}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "fred"}) - members_ids = [m.id for m in - models.Project.query.get("raclette").members] + members_ids = [m.id for m in models.Project.query.get("raclette").members] # create a bill - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': members_ids[0], - 'payed_for': members_ids, - 'amount': '25', - }) + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": members_ids[0], + "payed_for": members_ids, + "amount": "25", + }, + ) models.Project.query.get("raclette") bill = models.Bill.query.one() self.assertEqual(bill.amount, 25) # edit the bill - self.client.post("/raclette/edit/%s" % bill.id, data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': members_ids[0], - 'payed_for': members_ids, - 'amount': '10', - }) + self.client.post( + "/raclette/edit/%s" % bill.id, + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": members_ids[0], + "payed_for": members_ids, + "amount": "10", + }, + ) bill = models.Bill.query.one() self.assertEqual(bill.amount, 10, "bill edition") @@ -548,81 +598,103 @@ class BudgetTestCase(IhatemoneyTestCase): self.assertEqual(0, len(models.Bill.query.all()), "bill deletion") # test balance - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': members_ids[0], - 'payed_for': members_ids, - 'amount': '19', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': members_ids[1], - 'payed_for': members_ids[0], - 'amount': '20', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': members_ids[1], - 'payed_for': members_ids, - 'amount': '17', - }) + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": members_ids[0], + "payed_for": members_ids, + "amount": "19", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": members_ids[1], + "payed_for": members_ids[0], + "amount": "20", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": members_ids[1], + "payed_for": members_ids, + "amount": "17", + }, + ) balance = models.Project.query.get("raclette").balance self.assertEqual(set(balance.values()), set([19.0, -19.0])) # Bill with negative amount - self.client.post("/raclette/add", data={ - 'date': '2011-08-12', - 'what': 'fromage à raclette', - 'payer': members_ids[0], - 'payed_for': members_ids, - 'amount': '-25' - }) - bill = models.Bill.query.filter(models.Bill.date == '2011-08-12')[0] + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-12", + "what": "fromage à raclette", + "payer": members_ids[0], + "payed_for": members_ids, + "amount": "-25", + }, + ) + bill = models.Bill.query.filter(models.Bill.date == "2011-08-12")[0] self.assertEqual(bill.amount, -25) # add a bill with a comma - self.client.post("/raclette/add", data={ - 'date': '2011-08-01', - 'what': 'fromage à raclette', - 'payer': members_ids[0], - 'payed_for': members_ids, - 'amount': '25,02', - }) - bill = models.Bill.query.filter(models.Bill.date == '2011-08-01')[0] + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-01", + "what": "fromage à raclette", + "payer": members_ids[0], + "payed_for": members_ids, + "amount": "25,02", + }, + ) + bill = models.Bill.query.filter(models.Bill.date == "2011-08-01")[0] self.assertEqual(bill.amount, 25.02) def test_weighted_balance(self): self.post_project("raclette") # add two persons - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - self.client.post("/raclette/members/add", data={'name': 'freddy familly', 'weight': 4}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post( + "/raclette/members/add", data={"name": "freddy familly", "weight": 4} + ) - members_ids = [m.id for m in - models.Project.query.get("raclette").members] + members_ids = [m.id for m in models.Project.query.get("raclette").members] # test balance - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': members_ids[0], - 'payed_for': members_ids, - 'amount': '10', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'pommes de terre', - 'payer': members_ids[1], - 'payed_for': members_ids, - 'amount': '10', - }) + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": members_ids[0], + "payed_for": members_ids, + "amount": "10", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "pommes de terre", + "payer": members_ids[1], + "payed_for": members_ids, + "amount": "10", + }, + ) balance = models.Project.query.get("raclette").balance self.assertEqual(set(balance.values()), set([6, -6])) @@ -631,8 +703,8 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # Add two times the same person (with a space at the end). - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - self.client.post("/raclette/members/add", data={'name': 'alexis '}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "alexis "}) members = models.Project.query.get("raclette").members self.assertEqual(len(members), 1) @@ -641,61 +713,74 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add two persons - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - self.client.post("/raclette/members/add", data={'name': 'tata', 'weight': 1}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "tata", "weight": 1}) resp = self.client.get("/raclette/") - self.assertIn('extra-info', resp.data.decode('utf-8')) + self.assertIn("extra-info", resp.data.decode("utf-8")) - self.client.post("/raclette/members/add", data={'name': 'freddy familly', 'weight': 4}) + self.client.post( + "/raclette/members/add", data={"name": "freddy familly", "weight": 4} + ) resp = self.client.get("/raclette/") - self.assertNotIn('extra-info', resp.data.decode('utf-8')) + self.assertNotIn("extra-info", resp.data.decode("utf-8")) def test_negative_weight(self): self.post_project("raclette") # Add one user and edit it to have a negative share - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - resp = self.client.post("/raclette/members/1/edit", data={'name': 'alexis', 'weight': -1}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + resp = self.client.post( + "/raclette/members/1/edit", data={"name": "alexis", "weight": -1} + ) # An error should be generated, and its weight should still be 1. - self.assertIn('<p class="alert alert-danger">', resp.data.decode('utf-8')) - self.assertEqual(len(models.Project.query.get('raclette').members), 1) - self.assertEqual(models.Project.query.get('raclette').members[0].weight, 1) + self.assertIn('<p class="alert alert-danger">', resp.data.decode("utf-8")) + self.assertEqual(len(models.Project.query.get("raclette").members), 1) + self.assertEqual(models.Project.query.get("raclette").members[0].weight, 1) def test_rounding(self): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - self.client.post("/raclette/members/add", data={'name': 'fred'}) - self.client.post("/raclette/members/add", data={'name': 'tata'}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "fred"}) + self.client.post("/raclette/members/add", data={"name": "tata"}) # create bills - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': 1, - 'payed_for': [1, 2, 3], - 'amount': '24.36', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'red wine', - 'payer': 2, - 'payed_for': [1], - 'amount': '19.12', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'delicatessen', - 'payer': 1, - 'payed_for': [1, 2], - 'amount': '22', - }) + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": 1, + "payed_for": [1, 2, 3], + "amount": "24.36", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "red wine", + "payer": 2, + "payed_for": [1], + "amount": "19.12", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "delicatessen", + "payer": 1, + "payed_for": [1, 2], + "amount": "22", + }, + ) balance = models.Project.query.get("raclette").balance result = {} @@ -714,45 +799,46 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") new_data = { - 'name': 'Super raclette party!', - 'contact_email': 'alexis@notmyidea.org', - 'password': 'didoudida' + "name": "Super raclette party!", + "contact_email": "alexis@notmyidea.org", + "password": "didoudida", } - resp = self.client.post("/raclette/edit", data=new_data, - follow_redirects=True) + resp = self.client.post("/raclette/edit", data=new_data, follow_redirects=True) self.assertEqual(resp.status_code, 200) project = models.Project.query.get("raclette") - self.assertEqual(project.name, new_data['name']) - self.assertEqual(project.contact_email, new_data['contact_email']) - self.assertTrue(check_password_hash(project.password, new_data['password'])) + self.assertEqual(project.name, new_data["name"]) + self.assertEqual(project.contact_email, new_data["contact_email"]) + self.assertTrue(check_password_hash(project.password, new_data["password"])) # Editing a project with a wrong email address should fail - new_data['contact_email'] = 'wrong_email' + new_data["contact_email"] = "wrong_email" - resp = self.client.post("/raclette/edit", data=new_data, - follow_redirects=True) - self.assertIn("Invalid email address", resp.data.decode('utf-8')) + resp = self.client.post("/raclette/edit", data=new_data, follow_redirects=True) + self.assertIn("Invalid email address", resp.data.decode("utf-8")) def test_dashboard(self): # test that the dashboard is deactivated by default resp = self.client.post( "/admin?goto=%2Fdashboard", - data={'admin_password': 'adminpass'}, - follow_redirects=True + data={"admin_password": "adminpass"}, + follow_redirects=True, ) - self.assertIn('<div class="alert alert-danger">', resp.data.decode('utf-8')) + self.assertIn('<div class="alert alert-danger">', resp.data.decode("utf-8")) # test access to the dashboard when it is activated - self.app.config['ACTIVATE_ADMIN_DASHBOARD'] = True - self.app.config['ADMIN_PASSWORD'] = generate_password_hash("adminpass") + self.app.config["ACTIVATE_ADMIN_DASHBOARD"] = True + self.app.config["ADMIN_PASSWORD"] = generate_password_hash("adminpass") resp = self.client.post( "/admin?goto=%2Fdashboard", - data={'admin_password': 'adminpass'}, - follow_redirects=True + data={"admin_password": "adminpass"}, + follow_redirects=True, + ) + self.assertIn( + "<thead><tr><th>Project</th><th>Number of members", + resp.data.decode("utf-8"), ) - self.assertIn('<thead><tr><th>Project</th><th>Number of members', resp.data.decode('utf-8')) def test_statistics_page(self): self.post_project("raclette") @@ -763,58 +849,75 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={'name': 'alexis', 'weight': 2}) - self.client.post("/raclette/members/add", data={'name': 'fred'}) - self.client.post("/raclette/members/add", data={'name': 'tata'}) + self.client.post("/raclette/members/add", data={"name": "alexis", "weight": 2}) + self.client.post("/raclette/members/add", data={"name": "fred"}) + self.client.post("/raclette/members/add", data={"name": "tata"}) # Add a member with a balance=0 : - self.client.post("/raclette/members/add", data={'name': 'toto'}) + self.client.post("/raclette/members/add", data={"name": "toto"}) # create bills - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': 1, - 'payed_for': [1, 2, 3], - 'amount': '10.0', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'red wine', - 'payer': 2, - 'payed_for': [1], - 'amount': '20', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'delicatessen', - 'payer': 1, - 'payed_for': [1, 2], - 'amount': '10', - }) + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": 1, + "payed_for": [1, 2, 3], + "amount": "10.0", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "red wine", + "payer": 2, + "payed_for": [1], + "amount": "20", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "delicatessen", + "payer": 1, + "payed_for": [1, 2], + "amount": "10", + }, + ) response = self.client.get("/raclette/statistics") - self.assertIn("<td>alexis</td>\n " - + "<td>20.00</td>\n " - + "<td>31.67</td>\n " - + "<td>-11.67</td>\n", - response.data.decode('utf-8')) - self.assertIn("<td>fred</td>\n " - + "<td>20.00</td>\n " - + "<td>5.83</td>\n " - + "<td>14.17</td>\n", - response.data.decode('utf-8')) - self.assertIn("<td>tata</td>\n " - + "<td>0.00</td>\n " - + "<td>2.50</td>\n " - + "<td>-2.50</td>\n", - response.data.decode('utf-8')) - self.assertIn("<td>toto</td>\n " - + "<td>0.00</td>\n " - + "<td>0.00</td>\n " - + "<td>0.00</td>\n", - response.data.decode('utf-8')) + self.assertIn( + "<td>alexis</td>\n " + + "<td>20.00</td>\n " + + "<td>31.67</td>\n " + + "<td>-11.67</td>\n", + response.data.decode("utf-8"), + ) + self.assertIn( + "<td>fred</td>\n " + + "<td>20.00</td>\n " + + "<td>5.83</td>\n " + + "<td>14.17</td>\n", + response.data.decode("utf-8"), + ) + self.assertIn( + "<td>tata</td>\n " + + "<td>0.00</td>\n " + + "<td>2.50</td>\n " + + "<td>-2.50</td>\n", + response.data.decode("utf-8"), + ) + self.assertIn( + "<td>toto</td>\n " + + "<td>0.00</td>\n " + + "<td>0.00</td>\n " + + "<td>0.00</td>\n", + response.data.decode("utf-8"), + ) def test_settle_page(self): self.post_project("raclette") @@ -825,43 +928,52 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - self.client.post("/raclette/members/add", data={'name': 'fred'}) - self.client.post("/raclette/members/add", data={'name': 'tata'}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "fred"}) + self.client.post("/raclette/members/add", data={"name": "tata"}) # Add a member with a balance=0 : - self.client.post("/raclette/members/add", data={'name': 'toto'}) + self.client.post("/raclette/members/add", data={"name": "toto"}) # create bills - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'fromage à raclette', - 'payer': 1, - 'payed_for': [1, 2, 3], - 'amount': '10.0', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'red wine', - 'payer': 2, - 'payed_for': [1], - 'amount': '20', - }) - - self.client.post("/raclette/add", data={ - 'date': '2011-08-10', - 'what': 'delicatessen', - 'payer': 1, - 'payed_for': [1, 2], - 'amount': '10', - }) - project = models.Project.query.get('raclette') + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "fromage à raclette", + "payer": 1, + "payed_for": [1, 2, 3], + "amount": "10.0", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "red wine", + "payer": 2, + "payed_for": [1], + "amount": "20", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2011-08-10", + "what": "delicatessen", + "payer": 1, + "payed_for": [1, 2], + "amount": "10", + }, + ) + project = models.Project.query.get("raclette") transactions = project.get_transactions_to_settle_bill() members = defaultdict(int) # We should have the same values between transactions and project balances for t in transactions: - members[t['ower']] -= t['amount'] - members[t['receiver']] += t['amount'] + members[t["ower"]] -= t["amount"] + members[t["receiver"]] += t["amount"] balance = models.Project.query.get("raclette").balance for m, a in members.items(): assert abs(a - balance[m.id]) < 0.01 @@ -871,116 +983,141 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={'name': 'alexis'}) - self.client.post("/raclette/members/add", data={'name': 'fred'}) - self.client.post("/raclette/members/add", data={'name': 'tata'}) + self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "fred"}) + self.client.post("/raclette/members/add", data={"name": "tata"}) # create bills - self.client.post("/raclette/add", data={ - 'date': '2016-12-31', - 'what': 'fromage à raclette', - 'payer': 1, - 'payed_for': [1, 2, 3], - 'amount': '10.0', - }) - - self.client.post("/raclette/add", data={ - 'date': '2016-12-31', - 'what': 'red wine', - 'payer': 2, - 'payed_for': [1, 3], - 'amount': '20', - }) - - self.client.post("/raclette/add", data={ - 'date': '2017-01-01', - 'what': 'refund', - 'payer': 3, - 'payed_for': [2], - 'amount': '13.33', - }) - project = models.Project.query.get('raclette') + self.client.post( + "/raclette/add", + data={ + "date": "2016-12-31", + "what": "fromage à raclette", + "payer": 1, + "payed_for": [1, 2, 3], + "amount": "10.0", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2016-12-31", + "what": "red wine", + "payer": 2, + "payed_for": [1, 3], + "amount": "20", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2017-01-01", + "what": "refund", + "payer": 3, + "payed_for": [2], + "amount": "13.33", + }, + ) + project = models.Project.query.get("raclette") transactions = project.get_transactions_to_settle_bill() # There should not be any zero-amount transfer after rounding for t in transactions: - rounded_amount = round(t['amount'], 2) - self.assertNotEqual(0.0, rounded_amount, - msg='%f is equal to zero after rounding' % t['amount']) + rounded_amount = round(t["amount"], 2) + self.assertNotEqual( + 0.0, + rounded_amount, + msg="%f is equal to zero after rounding" % t["amount"], + ) def test_export(self): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={'name': 'alexis', 'weight': 2}) - self.client.post("/raclette/members/add", data={'name': 'fred'}) - self.client.post("/raclette/members/add", data={'name': 'tata'}) - self.client.post("/raclette/members/add", data={'name': 'pépé'}) + self.client.post("/raclette/members/add", data={"name": "alexis", "weight": 2}) + self.client.post("/raclette/members/add", data={"name": "fred"}) + self.client.post("/raclette/members/add", data={"name": "tata"}) + self.client.post("/raclette/members/add", data={"name": "pépé"}) # create bills - self.client.post("/raclette/add", data={ - 'date': '2016-12-31', - 'what': 'fromage à raclette', - 'payer': 1, - 'payed_for': [1, 2, 3, 4], - 'amount': '10.0', - }) - - self.client.post("/raclette/add", data={ - 'date': '2016-12-31', - 'what': 'red wine', - 'payer': 2, - 'payed_for': [1, 3], - 'amount': '200', - }) - - self.client.post("/raclette/add", data={ - 'date': '2017-01-01', - 'what': 'refund', - 'payer': 3, - 'payed_for': [2], - 'amount': '13.33', - }) + self.client.post( + "/raclette/add", + data={ + "date": "2016-12-31", + "what": "fromage à raclette", + "payer": 1, + "payed_for": [1, 2, 3, 4], + "amount": "10.0", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2016-12-31", + "what": "red wine", + "payer": 2, + "payed_for": [1, 3], + "amount": "200", + }, + ) + + self.client.post( + "/raclette/add", + data={ + "date": "2017-01-01", + "what": "refund", + "payer": 3, + "payed_for": [2], + "amount": "13.33", + }, + ) # generate json export of bills resp = self.client.get("/raclette/export/bills.json") - expected = [{ - 'date': '2017-01-01', - 'what': 'refund', - 'amount': 13.33, - 'payer_name': 'tata', - 'payer_weight': 1.0, - 'owers': ['fred'] - }, { - 'date': '2016-12-31', - 'what': 'red wine', - 'amount': 200.0, - 'payer_name': 'fred', - 'payer_weight': 1.0, - 'owers': ['alexis', 'tata'] - }, { - 'date': '2016-12-31', - 'what': 'fromage \xe0 raclette', - 'amount': 10.0, - 'payer_name': 'alexis', - 'payer_weight': 2.0, - 'owers': ['alexis', 'fred', 'tata', 'p\xe9p\xe9'] - }] - self.assertEqual(json.loads(resp.data.decode('utf-8')), expected) + expected = [ + { + "date": "2017-01-01", + "what": "refund", + "amount": 13.33, + "payer_name": "tata", + "payer_weight": 1.0, + "owers": ["fred"], + }, + { + "date": "2016-12-31", + "what": "red wine", + "amount": 200.0, + "payer_name": "fred", + "payer_weight": 1.0, + "owers": ["alexis", "tata"], + }, + { + "date": "2016-12-31", + "what": "fromage \xe0 raclette", + "amount": 10.0, + "payer_name": "alexis", + "payer_weight": 2.0, + "owers": ["alexis", "fred", "tata", "p\xe9p\xe9"], + }, + ] + self.assertEqual(json.loads(resp.data.decode("utf-8")), expected) # generate csv export of bills resp = self.client.get("/raclette/export/bills.csv") expected = [ "date,what,amount,payer_name,payer_weight,owers", "2017-01-01,refund,13.33,tata,1.0,fred", - "2016-12-31,red wine,200.0,fred,1.0,\"alexis, tata\"", - "2016-12-31,fromage à raclette,10.0,alexis,2.0,\"alexis, fred, tata, pépé\""] - received_lines = resp.data.decode('utf-8').split("\n") + '2016-12-31,red wine,200.0,fred,1.0,"alexis, tata"', + '2016-12-31,fromage à raclette,10.0,alexis,2.0,"alexis, fred, tata, pépé"', + ] + received_lines = resp.data.decode("utf-8").split("\n") for i, line in enumerate(expected): self.assertEqual( - set(line.split(",")), - set(received_lines[i].strip("\r").split(",")) + set(line.split(",")), set(received_lines[i].strip("\r").split(",")) ) # generate json export of transactions @@ -991,7 +1128,7 @@ class BudgetTestCase(IhatemoneyTestCase): {"amount": 127.33, "receiver": "fred", "ower": "alexis"}, ] - self.assertEqual(json.loads(resp.data.decode('utf-8')), expected) + self.assertEqual(json.loads(resp.data.decode("utf-8")), expected) # generate csv export of transactions resp = self.client.get("/raclette/export/transactions.csv") @@ -1002,12 +1139,11 @@ class BudgetTestCase(IhatemoneyTestCase): "55.34,fred,tata", "127.33,fred,alexis", ] - received_lines = resp.data.decode('utf-8').split("\n") + received_lines = resp.data.decode("utf-8").split("\n") for i, line in enumerate(expected): self.assertEqual( - set(line.split(",")), - set(received_lines[i].strip("\r").split(",")) + set(line.split(",")), set(received_lines[i].strip("\r").split(",")) ) # wrong export_format should return a 404 @@ -1024,22 +1160,30 @@ class APITestCase(IhatemoneyTestCase): password = password or name contact = contact or "%s@notmyidea.org" % name - return self.client.post("/api/projects", data={ - 'name': name, - 'id': id, - 'password': password, - 'contact_email': contact - }) + return self.client.post( + "/api/projects", + data={ + "name": name, + "id": id, + "password": password, + "contact_email": contact, + }, + ) def api_add_member(self, project, name, weight=1): - self.client.post("/api/projects/%s/members" % project, - data={"name": name, "weight": weight}, - headers=self.get_auth(project)) + self.client.post( + "/api/projects/%s/members" % project, + data={"name": name, "weight": weight}, + headers=self.get_auth(project), + ) def get_auth(self, username, password=None): password = password or username - base64string = base64.encodebytes( - ('%s:%s' % (username, password)).encode('utf-8')).decode('utf-8').replace('\n', '') + base64string = ( + base64.encodebytes(("%s:%s" % (username, password)).encode("utf-8")) + .decode("utf-8") + .replace("\n", "") + ) return {"Authorization": "Basic %s" % base64string} def test_cors_requests(self): @@ -1048,9 +1192,10 @@ class APITestCase(IhatemoneyTestCase): self.assertStatus(201, resp) # Try to do an OPTIONS requests and see if the headers are correct. - resp = self.client.options("/api/projects/raclette", - headers=self.get_auth("raclette")) - self.assertEqual(resp.headers['Access-Control-Allow-Origin'], '*') + resp = self.client.options( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) + self.assertEqual(resp.headers["Access-Control-Allow-Origin"], "*") def test_basic_auth(self): # create a project @@ -1063,32 +1208,33 @@ class APITestCase(IhatemoneyTestCase): # PUT / POST / DELETE / GET on the different resources # should also return a 401 - for verb in ('post',): + for verb in ("post",): for resource in ("/raclette/members", "/raclette/bills"): url = "/api/projects" + resource - self.assertStatus(401, getattr(self.client, verb)(url), - verb + resource) + self.assertStatus(401, getattr(self.client, verb)(url), verb + resource) - for verb in ('get', 'delete', 'put'): - for resource in ("/raclette", "/raclette/members/1", - "/raclette/bills/1"): + for verb in ("get", "delete", "put"): + for resource in ("/raclette", "/raclette/members/1", "/raclette/bills/1"): url = "/api/projects" + resource - self.assertStatus(401, getattr(self.client, verb)(url), - verb + resource) + self.assertStatus(401, getattr(self.client, verb)(url), verb + resource) def test_project(self): # wrong email should return an error - resp = self.client.post("/api/projects", data={ - 'name': "raclette", - 'id': "raclette", - 'password': "raclette", - 'contact_email': "not-an-email" - }) + resp = self.client.post( + "/api/projects", + data={ + "name": "raclette", + "id": "raclette", + "password": "raclette", + "contact_email": "not-an-email", + }, + ) self.assertTrue(400, resp.status_code) - self.assertEqual('{"contact_email": ["Invalid email address."]}\n', - resp.data.decode('utf-8')) + self.assertEqual( + '{"contact_email": ["Invalid email address."]}\n', resp.data.decode("utf-8") + ) # create it resp = self.api_create("raclette") @@ -1098,11 +1244,12 @@ class APITestCase(IhatemoneyTestCase): resp = self.api_create("raclette") self.assertTrue(400, resp.status_code) - self.assertIn('id', json.loads(resp.data.decode('utf-8'))) + self.assertIn("id", json.loads(resp.data.decode("utf-8"))) # get information about it - resp = self.client.get("/api/projects/raclette", - headers=self.get_auth("raclette")) + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) self.assertTrue(200, resp.status_code) expected = { @@ -1111,20 +1258,25 @@ class APITestCase(IhatemoneyTestCase): "contact_email": "raclette@notmyidea.org", "id": "raclette", } - decoded_resp = json.loads(resp.data.decode('utf-8')) + decoded_resp = json.loads(resp.data.decode("utf-8")) self.assertDictEqual(decoded_resp, expected) # edit should work - resp = self.client.put("/api/projects/raclette", data={ - "contact_email": "yeah@notmyidea.org", - "password": "raclette", - "name": "The raclette party", - }, headers=self.get_auth("raclette")) + resp = self.client.put( + "/api/projects/raclette", + data={ + "contact_email": "yeah@notmyidea.org", + "password": "raclette", + "name": "The raclette party", + }, + headers=self.get_auth("raclette"), + ) self.assertEqual(200, resp.status_code) - resp = self.client.get("/api/projects/raclette", - headers=self.get_auth("raclette")) + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) self.assertEqual(200, resp.status_code) expected = { @@ -1133,31 +1285,36 @@ class APITestCase(IhatemoneyTestCase): "members": [], "id": "raclette", } - decoded_resp = json.loads(resp.data.decode('utf-8')) + decoded_resp = json.loads(resp.data.decode("utf-8")) self.assertDictEqual(decoded_resp, expected) # password change is possible via API - resp = self.client.put("/api/projects/raclette", data={ - "contact_email": "yeah@notmyidea.org", - "password": "tartiflette", - "name": "The raclette party", - }, headers=self.get_auth("raclette")) + resp = self.client.put( + "/api/projects/raclette", + data={ + "contact_email": "yeah@notmyidea.org", + "password": "tartiflette", + "name": "The raclette party", + }, + headers=self.get_auth("raclette"), + ) self.assertEqual(200, resp.status_code) - resp = self.client.get("/api/projects/raclette", - headers=self.get_auth( - "raclette", "tartiflette")) + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette", "tartiflette") + ) self.assertEqual(200, resp.status_code) # delete should work - resp = self.client.delete("/api/projects/raclette", - headers=self.get_auth( - "raclette", "tartiflette")) + resp = self.client.delete( + "/api/projects/raclette", headers=self.get_auth("raclette", "tartiflette") + ) # get should return a 401 on an unknown resource - resp = self.client.get("/api/projects/raclette", - headers=self.get_auth("raclette")) + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) self.assertEqual(401, resp.status_code) def test_member(self): @@ -1165,94 +1322,110 @@ class APITestCase(IhatemoneyTestCase): self.api_create("raclette") # get the list of members (should be empty) - req = self.client.get("/api/projects/raclette/members", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/members", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual('[]\n', req.data.decode('utf-8')) + self.assertEqual("[]\n", req.data.decode("utf-8")) # add a member - req = self.client.post("/api/projects/raclette/members", data={ - "name": "Alexis" - }, headers=self.get_auth("raclette")) + req = self.client.post( + "/api/projects/raclette/members", + data={"name": "Alexis"}, + headers=self.get_auth("raclette"), + ) # the id of the new member should be returned self.assertStatus(201, req) - self.assertEqual("1\n", req.data.decode('utf-8')) + self.assertEqual("1\n", req.data.decode("utf-8")) # the list of members should contain one member - req = self.client.get("/api/projects/raclette/members", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/members", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual(len(json.loads(req.data.decode('utf-8'))), 1) + self.assertEqual(len(json.loads(req.data.decode("utf-8"))), 1) # Try to add another member with the same name. - req = self.client.post("/api/projects/raclette/members", data={ - "name": "Alexis" - }, headers=self.get_auth("raclette")) + req = self.client.post( + "/api/projects/raclette/members", + data={"name": "Alexis"}, + headers=self.get_auth("raclette"), + ) self.assertStatus(400, req) # edit the member - req = self.client.put("/api/projects/raclette/members/1", data={ - "name": "Fred", - "weight": 2, - }, headers=self.get_auth("raclette")) + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred", "weight": 2}, + headers=self.get_auth("raclette"), + ) self.assertStatus(200, req) # get should return the new name - req = self.client.get("/api/projects/raclette/members/1", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual("Fred", json.loads(req.data.decode('utf-8'))["name"]) - self.assertEqual(2, json.loads(req.data.decode('utf-8'))["weight"]) + self.assertEqual("Fred", json.loads(req.data.decode("utf-8"))["name"]) + self.assertEqual(2, json.loads(req.data.decode("utf-8"))["weight"]) # edit this member with same information # (test PUT idemopotence) - req = self.client.put("/api/projects/raclette/members/1", data={ - "name": "Fred" - }, headers=self.get_auth("raclette")) + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred"}, + headers=self.get_auth("raclette"), + ) self.assertStatus(200, req) # de-activate the user - req = self.client.put("/api/projects/raclette/members/1", data={ - "name": "Fred", - "activated": False, - }, headers=self.get_auth("raclette")) + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred", "activated": False}, + headers=self.get_auth("raclette"), + ) self.assertStatus(200, req) - req = self.client.get("/api/projects/raclette/members/1", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual(False, json.loads(req.data.decode('utf-8'))["activated"]) + self.assertEqual(False, json.loads(req.data.decode("utf-8"))["activated"]) # re-activate the user - req = self.client.put("/api/projects/raclette/members/1", data={ - "name": "Fred", - "activated": True, - }, headers=self.get_auth("raclette")) + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred", "activated": True}, + headers=self.get_auth("raclette"), + ) - req = self.client.get("/api/projects/raclette/members/1", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual(True, json.loads(req.data.decode('utf-8'))["activated"]) + self.assertEqual(True, json.loads(req.data.decode("utf-8"))["activated"]) # delete a member - req = self.client.delete("/api/projects/raclette/members/1", - headers=self.get_auth("raclette")) + req = self.client.delete( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) # the list of members should be empty - req = self.client.get("/api/projects/raclette/members", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/members", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual('[]\n', req.data.decode('utf-8')) + self.assertEqual("[]\n", req.data.decode("utf-8")) def test_bills(self): # create a project @@ -1264,29 +1437,35 @@ class APITestCase(IhatemoneyTestCase): self.api_add_member("raclette", "arnaud") # get the list of bills (should be empty) - req = self.client.get("/api/projects/raclette/bills", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/bills", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual("[]\n", req.data.decode('utf-8')) + self.assertEqual("[]\n", req.data.decode("utf-8")) # add a bill - req = self.client.post("/api/projects/raclette/bills", data={ - 'date': '2011-08-10', - 'what': 'fromage', - 'payer': "1", - 'payed_for': ["1", "2"], - 'amount': '25', - 'external_link': "https://raclette.fr" - }, headers=self.get_auth("raclette")) + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": "25", + "external_link": "https://raclette.fr", + }, + headers=self.get_auth("raclette"), + ) # should return the id self.assertStatus(201, req) - self.assertEqual(req.data.decode('utf-8'), "1\n") + self.assertEqual(req.data.decode("utf-8"), "1\n") # get this bill details - req = self.client.get("/api/projects/raclette/bills/1", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) # compare with the added info self.assertStatus(200, req) @@ -1295,56 +1474,68 @@ class APITestCase(IhatemoneyTestCase): "payer_id": 1, "owers": [ {"activated": True, "id": 1, "name": "alexis", "weight": 1}, - {"activated": True, "id": 2, "name": "fred", "weight": 1}], + {"activated": True, "id": 2, "name": "fred", "weight": 1}, + ], "amount": 25.0, "date": "2011-08-10", "id": 1, - 'external_link': "https://raclette.fr" + "external_link": "https://raclette.fr", } - got = json.loads(req.data.decode('utf-8')) + got = json.loads(req.data.decode("utf-8")) self.assertEqual( datetime.date.today(), - datetime.datetime.strptime(got["creation_date"], '%Y-%m-%d').date() + datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(), ) del got["creation_date"] self.assertDictEqual(expected, got) # the list of bills should length 1 - req = self.client.get("/api/projects/raclette/bills", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/bills", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual(1, len(json.loads(req.data.decode('utf-8')))) + self.assertEqual(1, len(json.loads(req.data.decode("utf-8")))) # edit with errors should return an error - req = self.client.put("/api/projects/raclette/bills/1", data={ - 'date': '201111111-08-10', # not a date - 'what': 'fromage', - 'payer': "1", - 'payed_for': ["1", "2"], - 'amount': '25', - 'external_link': "https://raclette.fr", - }, headers=self.get_auth("raclette")) + req = self.client.put( + "/api/projects/raclette/bills/1", + data={ + "date": "201111111-08-10", # not a date + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": "25", + "external_link": "https://raclette.fr", + }, + headers=self.get_auth("raclette"), + ) self.assertStatus(400, req) - self.assertEqual('{"date": ["This field is required."]}\n', req.data.decode('utf-8')) + self.assertEqual( + '{"date": ["This field is required."]}\n', req.data.decode("utf-8") + ) # edit a bill - req = self.client.put("/api/projects/raclette/bills/1", data={ - 'date': '2011-09-10', - 'what': 'beer', - 'payer': "2", - 'payed_for': ["1", "2"], - 'amount': '25', - 'external_link': "https://raclette.fr", - }, headers=self.get_auth("raclette")) + req = self.client.put( + "/api/projects/raclette/bills/1", + data={ + "date": "2011-09-10", + "what": "beer", + "payer": "2", + "payed_for": ["1", "2"], + "amount": "25", + "external_link": "https://raclette.fr", + }, + headers=self.get_auth("raclette"), + ) # check its fields - req = self.client.get("/api/projects/raclette/bills/1", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) creation_date = datetime.datetime.strptime( - json.loads(req.data.decode('utf-8'))["creation_date"], - '%Y-%m-%d' + json.loads(req.data.decode("utf-8"))["creation_date"], "%Y-%m-%d" ).date() expected = { @@ -1352,29 +1543,32 @@ class APITestCase(IhatemoneyTestCase): "payer_id": 2, "owers": [ {"activated": True, "id": 1, "name": "alexis", "weight": 1}, - {"activated": True, "id": 2, "name": "fred", "weight": 1}], + {"activated": True, "id": 2, "name": "fred", "weight": 1}, + ], "amount": 25.0, "date": "2011-09-10", - 'external_link': "https://raclette.fr", - "id": 1 - } + "external_link": "https://raclette.fr", + "id": 1, + } - got = json.loads(req.data.decode('utf-8')) + got = json.loads(req.data.decode("utf-8")) self.assertEqual( creation_date, - datetime.datetime.strptime(got["creation_date"], '%Y-%m-%d').date() + datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(), ) del got["creation_date"] self.assertDictEqual(expected, got) # delete a bill - req = self.client.delete("/api/projects/raclette/bills/1", - headers=self.get_auth("raclette")) + req = self.client.delete( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) # getting it should return a 404 - req = self.client.get("/api/projects/raclette/bills/1", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) self.assertStatus(404, req) def test_bills_with_calculation(self): @@ -1399,23 +1593,23 @@ class APITestCase(IhatemoneyTestCase): req = self.client.post( "/api/projects/raclette/bills", data={ - 'date': '2011-08-10', - 'what': 'fromage', - 'payer': "1", - 'payed_for': ["1", "2"], - 'amount': input_amount, + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": input_amount, }, - headers=self.get_auth("raclette") + headers=self.get_auth("raclette"), ) # should return the id self.assertStatus(201, req) - self.assertEqual(req.data.decode('utf-8'), "{}\n".format(id)) + self.assertEqual(req.data.decode("utf-8"), "{}\n".format(id)) # get this bill's details req = self.client.get( "/api/projects/raclette/bills/{}".format(id), - headers=self.get_auth("raclette") + headers=self.get_auth("raclette"), ) # compare with the added info @@ -1425,17 +1619,18 @@ class APITestCase(IhatemoneyTestCase): "payer_id": 1, "owers": [ {"activated": True, "id": 1, "name": "alexis", "weight": 1}, - {"activated": True, "id": 2, "name": "fred", "weight": 1}], + {"activated": True, "id": 2, "name": "fred", "weight": 1}, + ], "amount": expected_amount, "date": "2011-08-10", "id": id, - "external_link": '', + "external_link": "", } - got = json.loads(req.data.decode('utf-8')) + got = json.loads(req.data.decode("utf-8")) self.assertEqual( datetime.date.today(), - datetime.datetime.strptime(got["creation_date"], '%Y-%m-%d').date() + datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(), ) del got["creation_date"] self.assertDictEqual(expected, got) @@ -1450,13 +1645,17 @@ class APITestCase(IhatemoneyTestCase): ] for amount in erroneous_amounts: - req = self.client.post("/api/projects/raclette/bills", data={ - 'date': '2011-08-10', - 'what': 'fromage', - 'payer': "1", - 'payed_for': ["1", "2"], - 'amount': amount, - }, headers=self.get_auth("raclette")) + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": amount, + }, + headers=self.get_auth("raclette"), + ) self.assertStatus(400, req) def test_statistics(self): @@ -1468,30 +1667,50 @@ class APITestCase(IhatemoneyTestCase): self.api_add_member("raclette", "fred") # add a bill - req = self.client.post("/api/projects/raclette/bills", data={ - 'date': '2011-08-10', - 'what': 'fromage', - 'payer': "1", - 'payed_for': ["1", "2"], - 'amount': '25', - }, headers=self.get_auth("raclette")) + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": "25", + }, + headers=self.get_auth("raclette"), + ) # get the list of bills (should be empty) - req = self.client.get("/api/projects/raclette/statistics", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/statistics", headers=self.get_auth("raclette") + ) self.assertStatus(200, req) - self.assertEqual([ - {'balance': 12.5, - 'member': {'activated': True, 'id': 1, - 'name': 'alexis', 'weight': 1.0}, - 'paid': 25.0, - 'spent': 12.5}, - {'balance': -12.5, - 'member': {'activated': True, 'id': 2, - 'name': 'fred', 'weight': 1.0}, - 'paid': 0, - 'spent': 12.5}], - json.loads(req.data.decode('utf-8'))) + self.assertEqual( + [ + { + "balance": 12.5, + "member": { + "activated": True, + "id": 1, + "name": "alexis", + "weight": 1.0, + }, + "paid": 25.0, + "spent": 12.5, + }, + { + "balance": -12.5, + "member": { + "activated": True, + "id": 2, + "name": "fred", + "weight": 1.0, + }, + "paid": 0, + "spent": 12.5, + }, + ], + json.loads(req.data.decode("utf-8")), + ) def test_username_xss(self): # create a project @@ -1502,8 +1721,8 @@ class APITestCase(IhatemoneyTestCase): # add members self.api_add_member("raclette", "<script>") - result = self.client.get('/raclette/') - self.assertNotIn("<script>", result.data.decode('utf-8')) + result = self.client.get("/raclette/") + self.assertNotIn("<script>", result.data.decode("utf-8")) def test_weighted_bills(self): # create a project @@ -1515,20 +1734,24 @@ class APITestCase(IhatemoneyTestCase): self.api_add_member("raclette", "arnaud") # add a bill - req = self.client.post("/api/projects/raclette/bills", data={ - 'date': '2011-08-10', - 'what': "fromage", - 'payer': "1", - 'payed_for': ["1", "2"], - 'amount': '25', - }, headers=self.get_auth("raclette")) + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": "25", + }, + headers=self.get_auth("raclette"), + ) # get this bill details - req = self.client.get("/api/projects/raclette/bills/1", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) creation_date = datetime.datetime.strptime( - json.loads(req.data.decode('utf-8'))["creation_date"], - '%Y-%m-%d' + json.loads(req.data.decode("utf-8"))["creation_date"], "%Y-%m-%d" ).date() # compare with the added info @@ -1538,30 +1761,49 @@ class APITestCase(IhatemoneyTestCase): "payer_id": 1, "owers": [ {"activated": True, "id": 1, "name": "alexis", "weight": 1}, - {"activated": True, "id": 2, "name": "freddy familly", "weight": 4}], + {"activated": True, "id": 2, "name": "freddy familly", "weight": 4}, + ], "amount": 25.0, "date": "2011-08-10", "id": 1, - "external_link": '' + "external_link": "", } - got = json.loads(req.data.decode('utf-8')) + got = json.loads(req.data.decode("utf-8")) self.assertEqual( creation_date, - datetime.datetime.strptime(got["creation_date"], '%Y-%m-%d').date() + datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(), ) del got["creation_date"] self.assertDictEqual(expected, got) # getting it should return a 404 - req = self.client.get("/api/projects/raclette", - headers=self.get_auth("raclette")) + req = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) expected = { "members": [ - {"activated": True, "id": 1, "name": "alexis", "weight": 1.0, "balance": 20.0}, - {"activated": True, "id": 2, "name": "freddy familly", "weight": 4.0, - "balance": -20.0}, - {"activated": True, "id": 3, "name": "arnaud", "weight": 1.0, "balance": 0}, + { + "activated": True, + "id": 1, + "name": "alexis", + "weight": 1.0, + "balance": 20.0, + }, + { + "activated": True, + "id": 2, + "name": "freddy familly", + "weight": 4.0, + "balance": -20.0, + }, + { + "activated": True, + "id": 3, + "name": "arnaud", + "weight": 1.0, + "balance": 0, + }, ], "contact_email": "raclette@notmyidea.org", "id": "raclette", @@ -1569,25 +1811,24 @@ class APITestCase(IhatemoneyTestCase): } self.assertStatus(200, req) - decoded_req = json.loads(req.data.decode('utf-8')) + decoded_req = json.loads(req.data.decode("utf-8")) self.assertDictEqual(decoded_req, expected) class ServerTestCase(IhatemoneyTestCase): - def test_homepage(self): # See https://github.com/spiral-project/ihatemoney/pull/358 - self.app.config['APPLICATION_ROOT'] = '/' + self.app.config["APPLICATION_ROOT"] = "/" req = self.client.get("/") self.assertStatus(200, req) def test_unprefixed(self): - self.app.config['APPLICATION_ROOT'] = '/' + self.app.config["APPLICATION_ROOT"] = "/" req = self.client.get("/foo/") self.assertStatus(303, req) def test_prefixed(self): - self.app.config['APPLICATION_ROOT'] = '/foo' + self.app.config["APPLICATION_ROOT"] = "/foo" req = self.client.get("/foo/") self.assertStatus(200, req) @@ -1599,26 +1840,27 @@ class CommandTestCase(BaseTestCase): - produce something non-empty """ cmd = GenerateConfig() - for config_file in cmd.get_options()[0].kwargs['choices']: - with patch('sys.stdout', new=io.StringIO()) as stdout: + for config_file in cmd.get_options()[0].kwargs["choices"]: + with patch("sys.stdout", new=io.StringIO()) as stdout: cmd.run(config_file) print(stdout.getvalue()) self.assertNotEqual(len(stdout.getvalue().strip()), 0) def test_generate_password_hash(self): cmd = GeneratePasswordHash() - with patch('sys.stdout', new=io.StringIO()) as stdout, \ - patch('getpass.getpass', new=lambda prompt: 'secret'): # NOQA + with patch("sys.stdout", new=io.StringIO()) as stdout, patch( + "getpass.getpass", new=lambda prompt: "secret" + ): # NOQA cmd.run() print(stdout.getvalue()) self.assertEqual(len(stdout.getvalue().strip()), 189) def test_demo_project_deletion(self): - self.create_project('demo') - self.assertEquals(models.Project.query.get('demo').name, 'demo') + self.create_project("demo") + self.assertEquals(models.Project.query.get("demo").name, "demo") cmd = DeleteProject() - cmd.run('demo') + cmd.run("demo") self.assertEqual(len(models.Project.query.all()), 0) |
