terminal_test.dart 11.4 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter_tools/src/base/io.dart';
6 7
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
8
import 'package:flutter_tools/src/base/terminal.dart';
9
import 'package:test/fake.dart';
10

11
import '../../src/common.dart';
12 13

void main() {
14
  group('output preferences', () {
15 16 17 18 19 20 21 22
    testWithoutContext('can wrap output', () async {
      final BufferLogger bufferLogger = BufferLogger(
        outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40),
        terminal: TestTerminal(platform: FakePlatform()..stdoutSupportsAnsi = true),
      );
      bufferLogger.printStatus('0123456789' * 8);

      expect(bufferLogger.statusText, equals(('0123456789' * 4 + '\n') * 2));
23 24
    });

25 26 27 28 29
    testWithoutContext('can turn off wrapping', () async {
      final BufferLogger bufferLogger = BufferLogger(
        outputPreferences: OutputPreferences.test(wrapText: false),
        terminal: TestTerminal(platform: FakePlatform()..stdoutSupportsAnsi = true),
      );
30
      final String testString = '0123456789' * 20;
31 32 33
      bufferLogger.printStatus(testString);

      expect(bufferLogger.statusText, equals('$testString\n'));
34 35 36 37
    });
  });

  group('ANSI coloring and bold', () {
38
    late AnsiTerminal terminal;
39 40

    setUp(() {
41
      terminal = AnsiTerminal(
42
        stdio: Stdio(), // Danger, using real stdio.
43 44
        platform: FakePlatform()..stdoutSupportsAnsi = true,
      );
45 46
    });

47
    testWithoutContext('adding colors works', () {
48
      for (final TerminalColor color in TerminalColor.values) {
49 50 51 52 53 54 55
        expect(
          terminal.color('output', color),
          equals('${AnsiTerminal.colorCode(color)}output${AnsiTerminal.resetColor}'),
        );
      }
    });

56
    testWithoutContext('adding bold works', () {
57 58 59 60 61 62
      expect(
        terminal.bolden('output'),
        equals('${AnsiTerminal.bold}output${AnsiTerminal.resetBold}'),
      );
    });

63
    testWithoutContext('nesting bold within color works', () {
64 65 66 67 68 69 70 71 72 73
      expect(
        terminal.color(terminal.bolden('output'), TerminalColor.blue),
        equals('${AnsiTerminal.blue}${AnsiTerminal.bold}output${AnsiTerminal.resetBold}${AnsiTerminal.resetColor}'),
      );
      expect(
        terminal.color('non-bold ${terminal.bolden('output')} also non-bold', TerminalColor.blue),
        equals('${AnsiTerminal.blue}non-bold ${AnsiTerminal.bold}output${AnsiTerminal.resetBold} also non-bold${AnsiTerminal.resetColor}'),
      );
    });

74
    testWithoutContext('nesting color within bold works', () {
75 76 77 78 79 80 81 82 83 84
      expect(
        terminal.bolden(terminal.color('output', TerminalColor.blue)),
        equals('${AnsiTerminal.bold}${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.resetBold}'),
      );
      expect(
        terminal.bolden('non-color ${terminal.color('output', TerminalColor.blue)} also non-color'),
        equals('${AnsiTerminal.bold}non-color ${AnsiTerminal.blue}output${AnsiTerminal.resetColor} also non-color${AnsiTerminal.resetBold}'),
      );
    });

85
    testWithoutContext('nesting color within color works', () {
86 87 88 89 90 91 92 93 94 95
      expect(
        terminal.color(terminal.color('output', TerminalColor.blue), TerminalColor.magenta),
        equals('${AnsiTerminal.magenta}${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.magenta}${AnsiTerminal.resetColor}'),
      );
      expect(
        terminal.color('magenta ${terminal.color('output', TerminalColor.blue)} also magenta', TerminalColor.magenta),
        equals('${AnsiTerminal.magenta}magenta ${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.magenta} also magenta${AnsiTerminal.resetColor}'),
      );
    });

96
    testWithoutContext('nesting bold within bold works', () {
97 98 99 100 101 102 103 104 105 106 107
      expect(
        terminal.bolden(terminal.bolden('output')),
        equals('${AnsiTerminal.bold}output${AnsiTerminal.resetBold}'),
      );
      expect(
        terminal.bolden('bold ${terminal.bolden('output')} still bold'),
        equals('${AnsiTerminal.bold}bold output still bold${AnsiTerminal.resetBold}'),
      );
    });
  });

108
  group('character input prompt', () {
109
    late AnsiTerminal terminalUnderTest;
110 111

    setUp(() {
112
      terminalUnderTest = TestTerminal(stdio: FakeStdio());
113 114
    });

115
    testWithoutContext('character prompt throws if usesTerminalUi is false', () async {
116 117 118
      expect(terminalUnderTest.promptForCharInput(
        <String>['a', 'b', 'c'],
        prompt: 'Please choose something',
119
        logger: BufferLogger.test(),
Dan Field's avatar
Dan Field committed
120
      ), throwsStateError);
121 122
    });

123 124 125 126 127
    testWithoutContext('character prompt', () async {
      final BufferLogger bufferLogger = BufferLogger(
        terminal: terminalUnderTest,
        outputPreferences: OutputPreferences.test(),
      );
128
      terminalUnderTest.usesTerminalUi = true;
129 130 131 132
      mockStdInStream = Stream<String>.fromFutures(<Future<String>>[
        Future<String>.value('d'), // Not in accepted list.
        Future<String>.value('\n'), // Not in accepted list
        Future<String>.value('b'),
133
      ]).asBroadcastStream();
134 135 136
      final String choice = await terminalUnderTest.promptForCharInput(
        <String>['a', 'b', 'c'],
        prompt: 'Please choose something',
137
        logger: bufferLogger,
138
      );
139
      expect(choice, 'b');
140
      expect(
141
          bufferLogger.statusText,
142 143 144
          'Please choose something [a|b|c]: d\n'
          'Please choose something [a|b|c]: \n'
          'Please choose something [a|b|c]: b\n');
145 146
    });

147 148 149 150 151
    testWithoutContext('default character choice without displayAcceptedCharacters', () async {
      final BufferLogger bufferLogger = BufferLogger(
        terminal: terminalUnderTest,
        outputPreferences: OutputPreferences.test(),
      );
152
      terminalUnderTest.usesTerminalUi = true;
153 154
      mockStdInStream = Stream<String>.fromFutures(<Future<String>>[
        Future<String>.value('\n'), // Not in accepted list
155
      ]).asBroadcastStream();
156 157 158 159 160
      final String choice = await terminalUnderTest.promptForCharInput(
        <String>['a', 'b', 'c'],
        prompt: 'Please choose something',
        displayAcceptedCharacters: false,
        defaultChoiceIndex: 1, // which is b.
161
        logger: bufferLogger,
162
      );
163

164 165
      expect(choice, 'b');
      expect(
166 167 168
        bufferLogger.statusText,
        'Please choose something: \n'
      );
169
    });
170

171
    testWithoutContext('Does not set single char mode when a terminal is not attached', () {
172 173
      final Stdio stdio = FakeStdio()
        ..stdinHasTerminal = false;
174 175
      final AnsiTerminal ansiTerminal = AnsiTerminal(
        stdio: stdio,
176
        platform: const LocalPlatform(),
177
      );
178

179
      expect(() => ansiTerminal.singleCharMode = true, returnsNormally);
180
    });
181
  });
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

  testWithoutContext('AnsiTerminal.preferredStyle', () {
    final Stdio stdio = FakeStdio();
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform()).preferredStyle, 0); // Defaults to 0 for backwards compatibility.

    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  1)).preferredStyle, 0);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  2)).preferredStyle, 1);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  3)).preferredStyle, 2);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  4)).preferredStyle, 3);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  5)).preferredStyle, 4);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  6)).preferredStyle, 5);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  7)).preferredStyle, 5);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  8)).preferredStyle, 0);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  9)).preferredStyle, 1);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 10)).preferredStyle, 2);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 11)).preferredStyle, 3);

    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  1, 1)).preferredStyle, 0);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  2, 1)).preferredStyle, 1);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  3, 1)).preferredStyle, 2);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  4, 1)).preferredStyle, 3);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  5, 1)).preferredStyle, 4);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  6, 1)).preferredStyle, 6);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  7, 1)).preferredStyle, 6);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  8, 1)).preferredStyle, 0);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  9, 1)).preferredStyle, 1);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 10, 1)).preferredStyle, 2);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 11, 1)).preferredStyle, 3);

    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  1, 23)).preferredStyle, 0);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  2, 23)).preferredStyle, 1);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  3, 23)).preferredStyle, 2);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  4, 23)).preferredStyle, 3);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  5, 23)).preferredStyle, 4);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  6, 23)).preferredStyle, 28);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  7, 23)).preferredStyle, 28);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  8, 23)).preferredStyle, 0);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1,  9, 23)).preferredStyle, 1);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 10, 23)).preferredStyle, 2);
    expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 11, 23)).preferredStyle, 3);
  });
223 224
}

225
late Stream<String> mockStdInStream;
226 227

class TestTerminal extends AnsiTerminal {
228
  TestTerminal({
229
    Stdio? stdio,
230
    Platform platform = const LocalPlatform(),
231 232
    DateTime? now,
  }) : super(stdio: stdio ?? Stdio(), platform: platform, now: now ?? DateTime(2018));
233

234
  @override
235
  Stream<String> get keystrokes {
236 237
    return mockStdInStream;
  }
238 239

  bool singleCharMode = false;
240 241 242

  @override
  int get preferredStyle => 0;
243
}
244

245 246 247 248
class FakeStdio extends Fake implements Stdio {
  @override
  bool stdinHasTerminal = false;
}