import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:marianum_mobile/api/marianumcloud/talk/create_poll/create_poll_params.dart'; import 'package:marianum_mobile/api/marianumcloud/talk/get_poll/get_poll_state_response.dart'; import 'package:marianum_mobile/api/marianumcloud/talk/vote_poll/vote_poll_params.dart'; GetPollStateResponseObject _poll({ dynamic votes = const {}, String actorType = 'users', String actorId = 'creator', int status = pollStatusOpen, int resultMode = pollResultModePublic, int maxVotes = 1, List votedSelf = const [], int? numVoters, }) => GetPollStateResponseObject( 1, 'Frage?', const ['A', 'B'], votes, actorType, actorId, 'Creator', status, resultMode, maxVotes, votedSelf, numVoters, null, ); void main() { group('GetPollStateResponseObject.voteCounts', () { test('map input is returned as num map', () { final poll = _poll(votes: {'option-0': 2, 'option-1': 5}); expect(poll.voteCounts, {'option-0': 2, 'option-1': 5}); }); test('empty list (hidden results) becomes empty map', () { expect(_poll(votes: const []).voteCounts, isEmpty); }); test('null votes becomes empty map', () { expect(_poll(votes: null).voteCounts, isEmpty); }); test('non-num values are filtered out', () { final poll = _poll(votes: {'option-0': 3, 'option-1': 'x'}); expect(poll.voteCounts, {'option-0': 3}); }); }); group('GetPollStateResponseObject status/resultMode', () { test('isClosed reflects status', () { expect(_poll(status: pollStatusOpen).isClosed, isFalse); expect(_poll(status: pollStatusClosed).isClosed, isTrue); }); test('resultsHidden reflects resultMode', () { expect(_poll(resultMode: pollResultModePublic).resultsHidden, isFalse); expect(_poll(resultMode: pollResultModeHidden).resultsHidden, isTrue); }); }); group('GetPollStateResponseObject.canClose', () { test('creator may close', () { final poll = _poll(actorId: 'me'); expect(poll.canClose(selfId: 'me', participantType: 3), isTrue); }); test('moderator types may close', () { final poll = _poll(actorId: 'someone'); for (final type in [1, 2, 6]) { expect( poll.canClose(selfId: 'me', participantType: type), isTrue, reason: 'participantType $type should be allowed', ); } }); test('regular participant may not close', () { final poll = _poll(actorId: 'someone'); expect(poll.canClose(selfId: 'me', participantType: 3), isFalse); }); test('closed poll can never be closed again', () { final poll = _poll(actorId: 'me', status: pollStatusClosed); expect(poll.canClose(selfId: 'me', participantType: 1), isFalse); }); test('guest with matching id is not treated as creator', () { final poll = _poll(actorType: 'guests', actorId: 'me'); expect(poll.canClose(selfId: 'me', participantType: 3), isFalse); }); }); group('poll params serialization', () { // Regression: der ursprüngliche Bug entstand, weil optionIds nicht als // valides JSON serialisiert wurde und der Server ein leeres Array sah. test('VotePollParams encodes optionIds as a JSON array', () { final json = jsonEncode(VotePollParams(optionIds: [0, 2]).toJson()); expect(json, '{"optionIds":[0,2]}'); }); test('empty VotePollParams encodes an empty array', () { final json = jsonEncode(VotePollParams(optionIds: []).toJson()); expect(json, '{"optionIds":[]}'); }); test('CreatePollParams encodes all fields', () { final json = jsonEncode( CreatePollParams( question: 'Q?', options: const ['A', 'B'], resultMode: pollResultModeHidden, maxVotes: 0, ).toJson(), ); expect( json, '{"question":"Q?","options":["A","B"],"resultMode":1,"maxVotes":0}', ); }); }); }