Coverage for app/backend/src/tests/test_visible_users.py: 100%

80 statements  

« prev     ^ index     » next       coverage.py v7.14.2, created at 2026-06-21 09:29 +0000

1from typing import cast 

2 

3from sqlalchemy import select, update 

4from sqlalchemy.sql import func 

5 

6from couchers.context import CouchersContext 

7from couchers.db import session_scope 

8from couchers.models import FriendRelationship, User 

9from couchers.sql import users_visible, where_users_column_visible 

10from tests.fixtures.db import generate_user, make_friends, make_user_block, make_user_invisible 

11 

12 

13class _FakeContext: 

14 def __init__(self, user_id): 

15 self.user_id = user_id 

16 

17 def is_logged_in(self): 

18 return self.user_id is not None and self.user_id != 0 

19 

20 

21# Also tests different ways to make users invisible 

22def test_is_visible_property(db): 

23 user1, token1 = generate_user() 

24 user2, token2 = generate_user() 

25 user3, token3 = generate_user() 

26 user4, token4 = generate_user() 

27 user5, token5 = generate_user(delete_user=True) 

28 

29 with session_scope() as session: 

30 session.execute(update(User).where(User.id == user2.id).values(banned_at=func.now())) 

31 session.execute(update(User).where(User.id == user3.id).values(deleted_at=func.now())) 

32 session.execute(update(User).where(User.id == user4.id).values(banned_at=func.now())) 

33 

34 visible_users = session.execute(select(User.id).where(User.is_visible)).scalars().all() 

35 

36 assert visible_users[0] == user1.id 

37 

38 

39def test_select_dot_where_users_visible(db): 

40 user1, token1 = generate_user() 

41 user2, token2 = generate_user(delete_user=True) 

42 user3, token3 = generate_user() 

43 user4, token4 = generate_user() 

44 

45 make_user_block(user1, user3) 

46 make_user_block(user4, user1) 

47 

48 context = cast(CouchersContext, _FakeContext(user1.id)) 

49 with session_scope() as session: 

50 assert session.execute(select(func.count()).select_from(User).where(users_visible(context))).scalar_one() == 1 

51 

52 

53def test_select_dot_where_users_column_visible(db): 

54 user1, token1 = generate_user() 

55 user2, token2 = generate_user() 

56 user3, token3 = generate_user() 

57 user4, token4 = generate_user() 

58 user5, token5 = generate_user() 

59 

60 make_friends(user1, user2) 

61 make_friends(user1, user3) 

62 make_friends(user1, user4) 

63 make_friends(user1, user5) 

64 

65 make_user_invisible(user3.id) 

66 make_user_block(user1, user4) 

67 make_user_block(user5, user1) 

68 

69 context = cast(CouchersContext, _FakeContext(user1.id)) 

70 with session_scope() as session: 

71 assert ( 

72 session.execute( 

73 where_users_column_visible( 

74 select(func.count()).select_from(FriendRelationship), context, FriendRelationship.to_user_id 

75 ) 

76 ).scalar_one() 

77 == 1 

78 ) 

79 

80 

81def test_shadowed_user_hidden_from_others_visible_to_self(db): 

82 user1, _ = generate_user() 

83 user2, _ = generate_user() 

84 

85 with session_scope() as session: 

86 session.execute(update(User).where(User.id == user2.id).values(shadowed_at=func.now())) 

87 

88 other_context = cast(CouchersContext, _FakeContext(user1.id)) 

89 self_context = cast(CouchersContext, _FakeContext(user2.id)) 

90 anon_context = cast(CouchersContext, _FakeContext(None)) 

91 

92 with session_scope() as session: 

93 # user1 (other) does not see shadowed user2 

94 visible_to_other = ( 

95 session.execute(select(User.id).where(users_visible(other_context)).where(User.id == user2.id)) 

96 .scalars() 

97 .all() 

98 ) 

99 assert visible_to_other == [] 

100 

101 # user2 (self) sees themselves 

102 visible_to_self = ( 

103 session.execute(select(User.id).where(users_visible(self_context)).where(User.id == user2.id)) 

104 .scalars() 

105 .all() 

106 ) 

107 assert visible_to_self == [user2.id] 

108 

109 # anonymous viewer does not see shadowed user2 

110 visible_to_anon = ( 

111 session.execute(select(User.id).where(users_visible(anon_context)).where(User.id == user2.id)) 

112 .scalars() 

113 .all() 

114 ) 

115 assert visible_to_anon == [] 

116 

117 

118def test_shadowed_user_column_visible_with_self_exception(db): 

119 user1, _ = generate_user() 

120 user2, _ = generate_user() 

121 make_friends(user1, user2) 

122 

123 with session_scope() as session: 

124 session.execute(update(User).where(User.id == user2.id).values(shadowed_at=func.now())) 

125 

126 # user1 (other): friendship to shadowed user2 is filtered out 

127 context_other = cast(CouchersContext, _FakeContext(user1.id)) 

128 with session_scope() as session: 

129 count = session.execute( 

130 where_users_column_visible( 

131 select(func.count()).select_from(FriendRelationship), context_other, FriendRelationship.to_user_id 

132 ) 

133 ).scalar_one() 

134 assert count == 0 

135 

136 # user2 (self): can see the friendship pointing at themselves 

137 context_self = cast(CouchersContext, _FakeContext(user2.id)) 

138 with session_scope() as session: 

139 count = session.execute( 

140 where_users_column_visible( 

141 select(func.count()).select_from(FriendRelationship), context_self, FriendRelationship.to_user_id 

142 ) 

143 ).scalar_one() 

144 assert count == 1