Browse Source

do lost of things and work on bunny dashboard

testing
Burathar 4 years ago
parent
commit
554b8d4ec5
  1. 2
      app/main/routes.py
  2. 2
      app/main/tests/test_routes.py
  3. 16
      app/models/game_player.py
  4. 2
      app/models/objective.py
  5. 40
      app/models/tests/test_game.py
  6. 61
      app/models/tests/test_game_player.py
  7. 49
      app/models/tests/test_objective.py
  8. 75
      app/models/tests/test_user.py
  9. 47
      app/static/assets/leaflet/utils.js
  10. 40
      app/templates/game_bunny_dashboard.html
  11. 28
      app/templates/game_hunter_dashboard.html
  12. 26
      app/templates/game_owner_dashboard.html
  13. 113
      app/tests/test_models.py

2
app/main/routes.py

@ -67,7 +67,7 @@ def game_dashboard(game_name):
game=game, json=json, objective_encoder=ObjectiveMinimalEncoder, location_encoder=LocationEncoder) game=game, json=json, objective_encoder=ObjectiveMinimalEncoder, location_encoder=LocationEncoder)
if role == Role.bunny: if role == Role.bunny:
return render_template('game_bunny_dashboard.html', title='Game Dashboard', return render_template('game_bunny_dashboard.html', title='Game Dashboard',
game=game, json=json, objective_encoder=ObjectiveMinimalEncoder, location_encoder=LocationEncoder) game=game, json=json, location_encoder=LocationEncoder)
if role == Role.hunter: if role == Role.hunter:
return render_template('game_hunter_dashboard.html', title='Game Dashboard', return render_template('game_hunter_dashboard.html', title='Game Dashboard',
game=game, json=json, location_encoder=LocationEncoder) game=game, json=json, location_encoder=LocationEncoder)

2
app/main/tests/test_routes.py

@ -1,7 +1,7 @@
import unittest import unittest
from app import create_app, db from app import create_app, db
from app.models import Player, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder from app.models import User, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder
import app.main.routes as routes import app.main.routes as routes
from config import Config from config import Config

16
app/models/game_player.py

@ -1,3 +1,5 @@
import json
from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.schema import UniqueConstraint from sqlalchemy.schema import UniqueConstraint
@ -5,6 +7,7 @@ from app import db
from .role import Role from .role import Role
from .notification_player import NotificationPlayer from .notification_player import NotificationPlayer
from .player_found_objective import PlayerFoundObjective from .player_found_objective import PlayerFoundObjective
from .objective import Objective
class GamePlayer(db.Model): class GamePlayer(db.Model):
__tablename__ = 'game_player' __tablename__ = 'game_player'
@ -41,3 +44,16 @@ class GamePlayer(db.Model):
def locations_during_game(self): def locations_during_game(self):
# pylint: disable=no-member # pylint: disable=no-member
return self.user.locations_during_game(self.game) return self.user.locations_during_game(self.game)
def encode_objectives(self):
# pylint: disable=no-member
objectives = ['[']
for objective in self.game.objectives:
obj = {
'name' : objective.name,
'longitude' : objective.longitude,
'latitude' : objective.latitude,
'found' : objective in self.found_objectives}
objectives.append(json.dumps(obj))
objectives.append(',')
return ''.join(objectives)[:-1] + ']'

2
app/models/objective.py

@ -36,4 +36,4 @@ class ObjectiveMinimalEncoder(JSONEncoder):
'hash' : objective.hash, 'hash' : objective.hash,
'longitude' : objective.longitude, 'longitude' : objective.longitude,
'latitude' : objective.latitude 'latitude' : objective.latitude
} }

40
app/models/tests/test_game.py

@ -0,0 +1,40 @@
import unittest
from app import create_app, db
from app.models import User, Game, Role, GamePlayer
from config import Config
class TestConfig(Config):
TESTING = True
WTF_CSRF_ENABLED = False
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class GameCase(unittest.TestCase):
# implement this: https://stackoverflow.com/questions/47294304/how-to-mock-current-user-in-flask-templates
def setUp(self):
self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_is_game_owner(self):
g1 = Game(name='TestGame')
u1 = User(name='Henk')
u2 = User(name='Alfred')
g1.players.append(GamePlayer(user=u1, role=Role.owner))
g1.players.append(GamePlayer(user=u2, role=Role.bunny))
db.session.add(g1)
db.session.commit()
self.assertTrue(g1.owned_by(u1))
self.assertFalse(g1.owned_by(u2))
if __name__ == '__main__':
unittest.main(verbosity=2)

61
app/models/tests/test_game_player.py

@ -0,0 +1,61 @@
import unittest
import json
from app import create_app, db
from app.models import User, Game, Role, GamePlayer, Objective
from config import Config
class TestConfig(Config):
TESTING = True
WTF_CSRF_ENABLED = False
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class GamePlayerCase(unittest.TestCase):
# implement this: https://stackoverflow.com/questions/47294304/how-to-mock-current-user-in-flask-templates
def setUp(self):
self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_default(self):
g1 = Game(name='TestGame')
u1 = User(name='Henk')
p1 = GamePlayer(user=u1, role=Role.bunny)
o1 = Objective(name='Objective 1')
o2 = Objective(name='Objective 2')
o3 = Objective(name='Objective 3')
o1.set_hash()
o2.set_hash()
o3.set_hash()
g1.players.append(p1)
g1.objectives.append(o1)
g1.objectives.append(o2)
g1.objectives.append(o3)
p1.found_objectives.append(o1)
db.session.add(g1)
db.session.commit()
# Check if test initiaion succeeded
self.assertEqual(len(Game.query.first().objectives), 3)
self.assertEqual(User.query.first().user_games[0].found_objectives[0], o1)
# The actual Test
player_objectives = ('[{"name": "Objective 1", "longitude": null, "latitude": null, "found": true},'
'{"name": "Objective 2", "longitude": null, "latitude": null, "found": false},'
'{"name": "Objective 3", "longitude": null, "latitude": null, "found": false}]')
self.assertEqual(p1.encode_objectives(), player_objectives)
if __name__ == '__main__':
unittest.main(verbosity=2)

49
app/models/tests/test_objective.py

@ -0,0 +1,49 @@
import unittest
from app import create_app, db
from app.models import User, Game, Role, GamePlayer, Objective
from config import Config
class TestConfig(Config):
TESTING = True
WTF_CSRF_ENABLED = False
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class ObjectiveCase(unittest.TestCase):
# implement this: https://stackoverflow.com/questions/47294304/how-to-mock-current-user-in-flask-templates
def setUp(self):
self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_is_objective_owner(self):
g1 = Game(name='TestGame')
g2 = Game(name='AnotherGame')
u1 = User(name='Henk')
g1.players.append(GamePlayer(user=u1, role=Role.owner))
g2.players.append(GamePlayer(user=u1, role=Role.bunny))
o1 = Objective(name='o1')
o1.set_hash()
o2 = Objective(name='o2')
o2.set_hash()
g1.objectives.append(o1)
g2.objectives.append(o2)
db.session.add(g1)
db.session.add(g2)
db.session.commit()
self.assertTrue(o1.owned_by(u1))
self.assertFalse(o2.owned_by(u1))
if __name__ == '__main__':
unittest.main(verbosity=2)

75
app/models/tests/test_user.py

@ -0,0 +1,75 @@
import unittest
from app import create_app, db
from app.models import User, Game, GamePlayer, Role
from config import Config
class TestConfig(Config):
TESTING = True
WTF_CSRF_ENABLED = False
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class UserCase(unittest.TestCase):
# implement this: https://stackoverflow.com/questions/47294304/how-to-mock-current-user-in-flask-templates
def setUp(self):
self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_is_player_game_owner(self):
g1 = Game(name='TestGame')
g2 = Game(name='AnotherGame')
u1 = User(name='Henk')
u2 = User(name='Alfred')
u3 = User(name='Sasha')
g1.players.append(GamePlayer(user=u1, role=Role.owner))
g1.players.append(GamePlayer(user=u2, role=Role.bunny))
g2.players.append(GamePlayer(user=u1, role=Role.hunter))
g2.players.append(GamePlayer(user=u3, role=Role.bunny))
db.session.add(g1)
db.session.add(g2)
db.session.commit()
self.assertTrue(u1.owns_game_played_by(user=u2), "owner owns subject_player's game")
self.assertFalse(u1.owns_game_played_by(user=u3), "owner doesn't own subject_player's game")
self.assertTrue(u1.owns_game_played_by(user=u1), "owner owns it own's game")
def test_role_in_game(self):
g1 = Game(name='TestGame')
u1 = User(name='Henk')
u2 = User(name='Alfred')
u3 = User(name='Sasha')
u4 = User(name='Demian')
u5 = User(name='Karl')
g1.players.append(GamePlayer(user=u1, role=Role.owner))
g1.players.append(GamePlayer(user=u2, role=Role.bunny))
g1.players.append(GamePlayer(user=u3, role=Role.hunter))
g1.players.append(GamePlayer(user=u4, role=Role.none))
db.session.add(g1)
db.session.add(u5)
db.session.commit()
self.assertEqual(u1.role_in_game(g1), Role.owner)
self.assertEqual(u2.role_in_game(g1), Role.bunny)
self.assertEqual(u3.role_in_game(g1), Role.hunter)
self.assertEqual(u4.role_in_game(g1), Role.none)
self.assertEqual(u5.role_in_game(g1), None)
with self.assertRaises(AttributeError):
g1.get_role_for_game(None)
if __name__ == '__main__':
unittest.main(verbosity=2)

47
app/static/assets/leaflet/utils.js

@ -0,0 +1,47 @@
var greenIcon = new L.Icon({
iconUrl: '/static/assets/leaflet/images/marker-icon-2x-green.png',
shadowUrl: '/static/assets/leaflet/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var goldIcon = new L.Icon({
iconUrl: '/static/assets/leaflet/images/marker-icon-2x-gold.png',
shadowUrl: '/static/assets/leaflet/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
function addObjectiveMarker(map, objective){
var objectiveMarker = L.marker([
objective['latitude'],
objective['longitude']
])
if(objective['found']){
console.log('test')
objectiveMarker.setIcon(goldIcon)
}
objectiveMarker.addTo(map);
if(objective['hash']){
objectiveMarker.bindTooltip(`<b>${objective['name']}</b><br>
${objective['hash']}`).openPopup();
} else {
objectiveMarker.bindTooltip(`<b>${objective['name']}</b>`).openPopup();
}
}
function addPlayerMarker(map, player){
var playerMarker = L.marker([
player['latitude'],
player['longitude']
], {icon: greenIcon}).addTo(map);
var timestamp_utc = moment.utc(player['timestamp_utc']).toDate()
var timestamp_local = moment(timestamp_utc).local().format('YYYY-MM-DD HH:mm');
playerMarker.bindTooltip(`<b>${player['username']}</b><br>
${timestamp_local}`).openPopup();
}

40
app/templates/game_bunny_dashboard.html

@ -4,11 +4,12 @@
{{ super() }} {{ super() }}
<link rel="stylesheet" href="{{ url_for('static', filename='assets/leaflet/leaflet.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='assets/leaflet/leaflet.css') }}" />
<script src="{{ url_for('static', filename='assets/leaflet/leaflet.js') }}"></script> <script src="{{ url_for('static', filename='assets/leaflet/leaflet.js') }}"></script>
<script src="{{ url_for('static', filename='assets/leaflet/utils.js') }}"></script>
{% endblock %} {% endblock %}
{% block app_content %} {% block app_content %}
<h1>{{ game.name }} Dashboard</h1> <h1>{{ game.name }}: {{ current_user.name }}</h1>
{% include '_game_player_info.html' %}
<h2>Objective Locations:</h2> <h2>Objective Locations:</h2>
{% if game.objectives %} {% if game.objectives %}
<div class="table-responsive"> <div class="table-responsive">
@ -27,7 +28,7 @@
<td>{{ objective.name }}</td> <td>{{ objective.name }}</td>
<td>{{ objective.latitude }}</td> <td>{{ objective.latitude }}</td>
<td>{{ objective.longitude }}</td> <td>{{ objective.longitude }}</td>
<td>{{ 'Yes' if current_user.player_in(game) in objective.objective_found_by else 'No' }}</td> <td>{{ 'Yes' if objective in current_user.player_in(game).found_objectives else 'No' }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -57,36 +58,15 @@
attribution: 'Kaartgegevens &copy; <a href="https://kadaster.nl">Kadaster</a>' attribution: 'Kaartgegevens &copy; <a href="https://kadaster.nl">Kadaster</a>'
}).addTo( map ); }).addTo( map );
var objectives = JSON.parse('{{ json.dumps(game.objectives, cls=objective_encoder)|safe }}') var string = '{{ current_user.player_in(game).encode_objectives() |safe }}'
var objectives = JSON.parse(string)
for (var i = 0; i < objectives.length; i++){ for (var i = 0; i < objectives.length; i++){
var objectiveMarker = L.marker([ addObjectiveMarker(map, objectives[i])
objectives[i]['latitude'],
objectives[i]['longitude']
]).addTo(map);
objectiveMarker.bindTooltip(`<b>${objectives[i]['name']}</b><br>
${objectives[i]['hash']}`).openPopup();
} }
var greenIcon = new L.Icon({ var self = JSON.parse('{{ json.dumps(current_user.last_location(game), cls=location_encoder)|safe }}')
iconUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-icon-2x-green.png') }}", if (self){
shadowUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-shadow.png') }}", addPlayerMarker(map, self)
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var players = JSON.parse('{{ json.dumps(game.last_player_locations(), cls=location_encoder)|safe }}')
for (var i = 0; i < players.length; i++){
var playerMarker = L.marker([
players[i]['latitude'],
players[i]['longitude']
], {icon: greenIcon}).addTo(map);
var timestamp_utc = moment.utc(players[i]['timestamp_utc']).toDate()
var timestamp_local = moment(timestamp_utc).local().format('YYYY-MM-DD HH:mm');
playerMarker.bindTooltip(`<b>${players[i]['username']}</b><br>
${timestamp_local}`).openPopup();
} }
</script> </script>

28
app/templates/game_hunter_dashboard.html

@ -4,6 +4,7 @@
{{ super() }} {{ super() }}
<link rel="stylesheet" href="{{ url_for('static', filename='assets/leaflet/leaflet.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='assets/leaflet/leaflet.css') }}" />
<script src="{{ url_for('static', filename='assets/leaflet/leaflet.js') }}"></script> <script src="{{ url_for('static', filename='assets/leaflet/leaflet.js') }}"></script>
<script src="{{ url_for('static', filename='assets/leaflet/utils.js') }}"></script>
{% endblock %} {% endblock %}
{% block app_content %} {% block app_content %}
@ -63,26 +64,15 @@
L.tileLayer( 'https://geodata.nationaalgeoregister.nl/tiles/service/wmts/brtachtergrondkaartpastel/EPSG:3857/{z}/{x}/{y}.png', { L.tileLayer( 'https://geodata.nationaalgeoregister.nl/tiles/service/wmts/brtachtergrondkaartpastel/EPSG:3857/{z}/{x}/{y}.png', {
attribution: 'Kaartgegevens &copy; <a href="https://kadaster.nl">Kadaster</a>' attribution: 'Kaartgegevens &copy; <a href="https://kadaster.nl">Kadaster</a>'
}).addTo( map ); }).addTo( map );
var greenIcon = new L.Icon({
iconUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-icon-2x-green.png') }}",
shadowUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-shadow.png') }}",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var players = JSON.parse('{{ json.dumps(game.last_locations(game.bunnies()), cls=location_encoder)|safe }}') var bunnies = JSON.parse('{{ json.dumps(game.last_locations(game.bunnies()), cls=location_encoder)|safe }}')
for (var i = 0; i < players.length; i++){ for (var i = 0; i < bunnies.length; i++){
var playerMarker = L.marker([ addPlayerMarker(map, bunnies[i])
players[i]['latitude'], }
players[i]['longitude']
], {icon: greenIcon}).addTo(map); var self = JSON.parse('{{ json.dumps(current_user.last_location(game), cls=location_encoder)|safe }}')
var timestamp_utc = moment.utc(players[i]['timestamp_utc']).toDate() if (self){
var timestamp_local = moment(timestamp_utc).local().format('YYYY-MM-DD HH:mm'); addPlayerMarker(map, self)
playerMarker.bindTooltip(`<b>${players[i]['username']}</b><br>
${timestamp_local}`).openPopup();
} }
</script> </script>

26
app/templates/game_owner_dashboard.html

@ -4,6 +4,7 @@
{{ super() }} {{ super() }}
<link rel="stylesheet" href="{{ url_for('static', filename='assets/leaflet/leaflet.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='assets/leaflet/leaflet.css') }}" />
<script src="{{ url_for('static', filename='assets/leaflet/leaflet.js') }}"></script> <script src="{{ url_for('static', filename='assets/leaflet/leaflet.js') }}"></script>
<script src="{{ url_for('static', filename='assets/leaflet/utils.js') }}"></script>
{% endblock %} {% endblock %}
{% block app_content %} {% block app_content %}
@ -102,33 +103,12 @@
var objectives = JSON.parse('{{ json.dumps(game.objectives, cls=objective_encoder)|safe }}') var objectives = JSON.parse('{{ json.dumps(game.objectives, cls=objective_encoder)|safe }}')
for (var i = 0; i < objectives.length; i++){ for (var i = 0; i < objectives.length; i++){
var objectiveMarker = L.marker([ addObjectiveMarker(map, objectives[i])
objectives[i]['latitude'],
objectives[i]['longitude']
]).addTo(map);
objectiveMarker.bindTooltip(`<b>${objectives[i]['name']}</b><br>
${objectives[i]['hash']}`).openPopup();
} }
var greenIcon = new L.Icon({
iconUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-icon-2x-green.png') }}",
shadowUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-shadow.png') }}",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var players = JSON.parse('{{ json.dumps(game.last_player_locations(), cls=location_encoder)|safe }}') var players = JSON.parse('{{ json.dumps(game.last_player_locations(), cls=location_encoder)|safe }}')
for (var i = 0; i < players.length; i++){ for (var i = 0; i < players.length; i++){
var playerMarker = L.marker([ addPlayerMarker(map, players[i])
players[i]['latitude'],
players[i]['longitude']
], {icon: greenIcon}).addTo(map);
var timestamp_utc = moment.utc(players[i]['timestamp_utc']).toDate()
var timestamp_local = moment(timestamp_utc).local().format('YYYY-MM-DD HH:mm');
playerMarker.bindTooltip(`<b>${players[i]['username']}</b><br>
${timestamp_local}`).openPopup();
} }
</script> </script>

113
app/tests/test_models.py

@ -1,113 +0,0 @@
import unittest
from app import create_app, db
from app.models import User, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder
from config import Config
class TestConfig(Config):
TESTING = True
WTF_CSRF_ENABLED = False
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class ModelsCase(unittest.TestCase):
# implement this: https://stackoverflow.com/questions/47294304/how-to-mock-current-user-in-flask-templates
def setUp(self):
self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_is_game_owner(self):
g1 = Game(name='TestGame')
u1 = User(name='Henk')
u2 = User(name='Alfred')
g1.players.append(GamePlayer(player=u1, role=Role.owner))
g1.players.append(GamePlayer(player=u2, role=Role.bunny))
db.session.add(g1)
db.session.commit()
self.assertTrue(g1.is_game_owner(u1))
self.assertFalse(g1.is_game_owner(u2))
def test_is_player_game_owner(self):
g1 = Game(name='TestGame')
g2 = Game(name='AnotherGame')
u1 = User(name='Henk')
u2 = User(name='Alfred')
u3 = User(name='Sasha')
g1.players.append(GamePlayer(player=u1, role=Role.owner))
g1.players.append(GamePlayer(player=u2, role=Role.bunny))
g2.players.append(GamePlayer(player=u1, role=Role.hunter))
g2.players.append(GamePlayer(player=u3, role=Role.bunny))
db.session.add(g1)
db.session.add(g2)
db.session.commit()
self.assertTrue(u1.owns_game_played_by(player=u2), "owner owns subject_player's game")
self.assertFalse(u1.owns_game_played_by(player=u3), "owner doesn't own subject_player's game")
self.assertTrue(u1.owns_game_played_by(player=u1), "owner owns it own's game")
def test_is_objective_owner(self):
g1 = Game(name='TestGame')
g2 = Game(name='AnotherGame')
u1 = User(name='Henk')
g1.players.append(GamePlayer(player=u1, role=Role.owner))
g2.players.append(GamePlayer(player=u1, role=Role.bunny))
o1 = Objective(name='o1')
o1.set_hash()
o2 = Objective(name='o2')
o2.set_hash()
g1.objectives.append(o1)
g2.objectives.append(o2)
db.session.add(g1)
db.session.add(g2)
db.session.commit()
self.assertTrue(o1.owned_by(u1))
self.assertFalse(o2.owned_by(u1))
def test_role_in_game(self):
g1 = Game(name='TestGame')
u1 = User(name='Henk')
u2 = User(name='Alfred')
u3 = User(name='Sasha')
u4 = User(name='Demian')
u5 = User(name='Karl')
g1.players.append(GamePlayer(player=u1, role=Role.owner))
g1.players.append(GamePlayer(player=u2, role=Role.bunny))
g1.players.append(GamePlayer(player=u3, role=Role.hunter))
g1.players.append(GamePlayer(player=u4, role=Role.none))
db.session.add(g1)
db.session.add(u5)
db.session.commit()
self.assertEqual(u1.role_in_game(g1), Role.owner)
self.assertEqual(u2.role_in_game(g1), Role.bunny)
self.assertEqual(u3.role_in_game(g1), Role.hunter)
self.assertEqual(u4.role_in_game(g1), Role.none)
self.assertEqual(u5.role_in_game(g1), None)
with self.assertRaises(AttributeError):
g1.get_role_for_game(None)
if __name__ == '__main__':
unittest.main(verbosity=2)
Loading…
Cancel
Save