consolidate_response_test.dart 7.98 KB
Newer Older
1 2 3 4
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
@TestOn('!chrome')

7 8
import 'dart:async';
import 'dart:io';
9
import 'dart:typed_data';
10 11 12 13

import 'package:flutter/foundation.dart';
import 'package:mockito/mockito.dart';

14 15
import '../flutter_test_alternative.dart';

16 17
void main() {
  group(consolidateHttpClientResponseBytes, () {
18 19
    final Uint8List chunkOne = Uint8List.fromList(<int>[0, 1, 2, 3, 4, 5]);
    final Uint8List chunkTwo = Uint8List.fromList(<int>[6, 7, 8, 9, 10]);
20 21 22
    MockHttpClientResponse response;

    setUp(() {
23
      response = MockHttpClientResponse();
24
      when(response.compressionState).thenReturn(HttpClientResponseCompressionState.notCompressed);
25
      when(response.listen(
26
         any,
27 28
         onDone: anyNamed('onDone'),
         onError: anyNamed('onError'),
29
         cancelOnError: anyNamed('cancelOnError'),
30 31 32 33 34 35
      )).thenAnswer((Invocation invocation) {
        final void Function(List<int>) onData = invocation.positionalArguments[0];
        final void Function(Object) onError = invocation.namedArguments[#onError];
        final void Function() onDone = invocation.namedArguments[#onDone];
        final bool cancelOnError = invocation.namedArguments[#cancelOnError];

36 37
        return Stream<Uint8List>.fromIterable(
            <Uint8List>[chunkOne, chunkTwo]).listen(
38 39 40 41 42
          onData,
          onDone: onDone,
          onError: onError,
          cancelOnError: cancelOnError,
        );
43 44 45
      });
    });

46
    test('Converts an HttpClientResponse with contentLength to bytes', () async {
47 48 49
      when(response.contentLength)
          .thenReturn(chunkOne.length + chunkTwo.length);
      final List<int> bytes =
50
          await consolidateHttpClientResponseBytes(response);
51 52 53 54

      expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    });

55
    test('Converts a compressed HttpClientResponse with contentLength to bytes', () async {
56 57
      when(response.contentLength).thenReturn(chunkOne.length);
      final List<int> bytes =
58
          await consolidateHttpClientResponseBytes(response);
59 60 61 62

      expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    });

63
    test('Converts an HttpClientResponse without contentLength to bytes', () async {
64
      when(response.contentLength).thenReturn(-1);
65
      final List<int> bytes =
66
          await consolidateHttpClientResponseBytes(response);
67 68 69 70

      expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    });

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    test('Notifies onBytesReceived for every chunk of bytes', () async {
      final int syntheticTotal = (chunkOne.length + chunkTwo.length) * 2;
      when(response.contentLength).thenReturn(syntheticTotal);
      final List<int> records = <int>[];
      await consolidateHttpClientResponseBytes(
        response,
        onBytesReceived: (int cumulative, int total) {
          records.addAll(<int>[cumulative, total]);
        },
      );

      expect(records, <int>[
        chunkOne.length,
        syntheticTotal,
        chunkOne.length + chunkTwo.length,
        syntheticTotal,
      ]);
    });

90 91
    test('forwards errors from HttpClientResponse', () async {
      when(response.listen(
92
        any,
93 94
        onDone: anyNamed('onDone'),
        onError: anyNamed('onError'),
95
        cancelOnError: anyNamed('cancelOnError'),
96 97 98 99 100 101
      )).thenAnswer((Invocation invocation) {
        final void Function(List<int>) onData = invocation.positionalArguments[0];
        final void Function(Object) onError = invocation.namedArguments[#onError];
        final void Function() onDone = invocation.namedArguments[#onDone];
        final bool cancelOnError = invocation.namedArguments[#cancelOnError];

102 103
        return Stream<Uint8List>.fromFuture(
                Future<Uint8List>.error(Exception('Test Error')))
104 105 106 107 108 109
            .listen(
          onData,
          onDone: onDone,
          onError: onError,
          cancelOnError: cancelOnError,
        );
110 111 112
      });
      when(response.contentLength).thenReturn(-1);

113
      expect(consolidateHttpClientResponseBytes(response),
114
          throwsA(isInstanceOf<Exception>()));
115
    });
116 117 118 119 120 121 122 123 124 125 126 127 128 129

    test('Propagates error to Future return value if onBytesReceived throws', () async {
      when(response.contentLength).thenReturn(-1);
      final Future<List<int>> result = consolidateHttpClientResponseBytes(
        response,
        onBytesReceived: (int cumulative, int total) {
          throw 'misbehaving callback';
        },
      );

      expect(result, throwsA(equals('misbehaving callback')));
    });

    group('when gzipped', () {
130 131 132
      final Uint8List gzipped = gzip.encode(chunkOne.followedBy(chunkTwo).toList());
      final Uint8List gzippedChunkOne = gzipped.sublist(0, gzipped.length ~/ 2);
      final Uint8List gzippedChunkTwo = gzipped.sublist(gzipped.length ~/ 2);
133 134

      setUp(() {
135
        when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed);
136 137 138 139 140 141 142 143 144 145 146
        when(response.listen(
          any,
          onDone: anyNamed('onDone'),
          onError: anyNamed('onError'),
          cancelOnError: anyNamed('cancelOnError'),
        )).thenAnswer((Invocation invocation) {
          final void Function(List<int>) onData = invocation.positionalArguments[0];
          final void Function(Object) onError = invocation.namedArguments[#onError];
          final void Function() onDone = invocation.namedArguments[#onDone];
          final bool cancelOnError = invocation.namedArguments[#cancelOnError];

147 148
          return Stream<Uint8List>.fromIterable(
              <Uint8List>[gzippedChunkOne, gzippedChunkTwo]).listen(
149 150 151 152 153 154 155 156
            onData,
            onDone: onDone,
            onError: onError,
            cancelOnError: cancelOnError,
          );
        });
      });

157 158
      test('Uncompresses GZIP bytes if autoUncompress is true and response.compressionState is compressed', () async {
        when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed);
159
        when(response.contentLength).thenReturn(gzipped.length);
160
        final List<int> bytes = await consolidateHttpClientResponseBytes(response);
161 162 163
        expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
      });

164 165
      test('returns gzipped bytes if autoUncompress is false and response.compressionState is compressed', () async {
        when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed);
166
        when(response.contentLength).thenReturn(gzipped.length);
167
        final List<int> bytes = await consolidateHttpClientResponseBytes(response, autoUncompress: false);
168 169 170 171
        expect(bytes, gzipped);
      });

      test('Notifies onBytesReceived with gzipped numbers', () async {
172
        when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
        when(response.contentLength).thenReturn(gzipped.length);
        final List<int> records = <int>[];
        await consolidateHttpClientResponseBytes(
          response,
          onBytesReceived: (int cumulative, int total) {
            records.addAll(<int>[cumulative, total]);
          },
        );

        expect(records, <int>[
          gzippedChunkOne.length,
          gzipped.length,
          gzipped.length,
          gzipped.length,
        ]);
      });

190
      test('Notifies onBytesReceived with expectedContentLength of -1 if response.compressionState is decompressed', () async {
191
        final int syntheticTotal = (chunkOne.length + chunkTwo.length) * 2;
192
        when(response.compressionState).thenReturn(HttpClientResponseCompressionState.decompressed);
193 194 195 196 197 198 199 200 201 202 203
        when(response.contentLength).thenReturn(syntheticTotal);
        final List<int> records = <int>[];
        await consolidateHttpClientResponseBytes(
          response,
          onBytesReceived: (int cumulative, int total) {
            records.addAll(<int>[cumulative, total]);
          },
        );

        expect(records, <int>[
          gzippedChunkOne.length,
204
          null,
205
          gzipped.length,
206
          null,
207 208 209
        ]);
      });
    });
210 211 212
  });
}

213
class MockHttpClientResponse extends Mock implements HttpClientResponse {}