-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
252 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import 'package:sidekick_core/sidekick_core.dart'; | ||
import 'package:test/expect.dart'; | ||
import 'package:test/scaffolding.dart'; | ||
|
||
import 'util/cli_completion.dart'; | ||
import 'util/cli_runner.dart'; | ||
|
||
void main() { | ||
/// Tests in this file install a sidekick CLI named 'dashi' globally. | ||
/// To make sure this doesn't interfere with other tests, delete the symlink | ||
void uninstallGlobalCli() { | ||
// TODO use GlobalSidekickRoot.binDir when made available through updated sidekick_core dependency | ||
final userHome = Platform.environment['HOME']!; | ||
final sidekickBinDir = Directory('$userHome/.sidekick/bin'); | ||
// beware: sidekickBinDir.file('dashi').existsSync() always returns false because it's a link, not a file | ||
final dashiSymLink = sidekickBinDir | ||
.listSync() | ||
.firstOrNullWhere((element) => element.name == 'dashi'); | ||
|
||
if (dashiSymLink != null) { | ||
dashiSymLink.deleteSync(); | ||
} | ||
} | ||
|
||
setUp(uninstallGlobalCli); | ||
tearDown(uninstallGlobalCli); | ||
|
||
test('Prints info when tab completions are not installed', () async { | ||
await withSidekickCli((cli) async { | ||
final p = await cli.run([]); | ||
|
||
final command = yellow('dashi sidekick install-global'); | ||
final expectedMessage = | ||
'${cyan('Run')} $command ${cyan('to enable tab completion.')}'; | ||
|
||
final stdout = await p.stdoutStream().toList(); | ||
expect(stdout, contains(expectedMessage)); | ||
}); | ||
}); | ||
|
||
test('Tab prints completions', () async { | ||
await withSidekickCli( | ||
(cli) async { | ||
await expectLater( | ||
'dashi', | ||
cli.suggests({ | ||
'dart': 'Calls dart', | ||
'deps': 'Gets dependencies for all packages', | ||
'clean': 'Cleans the project', | ||
'analyze': 'Dart analyzes the whole project', | ||
'format': 'Formats all Dart files in the repository.', | ||
'sidekick': 'Manages the sidekick CLI', | ||
'--help': 'Print this usage information.', | ||
'--version': 'Print the sidekick version of this CLI.', | ||
}), | ||
); | ||
}, | ||
); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// Copied and adapted from package:cli_completion, file https://github.com/VeryGoodOpenSource/cli_completion/blob/a5b3571c03d964c08c6ce52b1cc907b2f93c0861/example/test/integration/utils.dart | ||
|
||
import 'dart:async'; | ||
import 'dart:io'; | ||
|
||
import 'package:sidekick_test/fake_stdio.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import 'cli_runner.dart'; | ||
|
||
extension RunCompletionCommandExtension on SidekickCli { | ||
/// Returns a matcher that matches if the tab completion of this CLI returns the given suggestions | ||
/// | ||
/// This is done by running the hidden 'completion' command of the CLI and checking its result | ||
Matcher suggests(Map<String, String?> suggestions, {int? whenCursorIsAt}) => | ||
_CliCompletionMatcher( | ||
suggestions, | ||
cursorIndex: whenCursorIsAt, | ||
cli: this, | ||
); | ||
|
||
Future<Map<String, String?>> _runCompletionCommand( | ||
String line, { | ||
int? cursorIndex, | ||
}) async { | ||
final map = <String, String?>{}; | ||
|
||
void onWriteln([Object? object]) { | ||
// Simulate the shell behavior of interpreting the output of the completion. | ||
final line = object! as String; | ||
|
||
// A regex that finds all colons, except the ones preceded by backslash | ||
final res = line.split(RegExp(r'(?<!\\):')); | ||
|
||
final description = res.length > 1 ? res[1] : null; | ||
|
||
map[res.first] = description; | ||
} | ||
|
||
final stdout = FakeStdoutStream(onWriteln: onWriteln); | ||
|
||
return await IOOverrides.runZoned( | ||
stdout: () => stdout, | ||
() async { | ||
final environmentOverride = { | ||
'SHELL': '/foo/bar/zsh', | ||
..._prepareEnvForLineInput(line, cursorIndex: cursorIndex), | ||
}; | ||
final process = | ||
await run(['completion'], environment: environmentOverride); | ||
final completions = await process.stdoutStream().toList(); | ||
final map = <String, String?>{}; | ||
|
||
for (final completionString in completions) { | ||
// A regex that finds all colons, except the ones preceded by backslash | ||
final res = completionString.split(RegExp(r'(?<!\\):')); | ||
|
||
final description = res.length > 1 ? res[1] : null; | ||
|
||
map[res.first] = description; | ||
} | ||
|
||
return map; | ||
}, | ||
); | ||
} | ||
} | ||
|
||
class _CliCompletionMatcher extends CustomMatcher { | ||
final SidekickCli cli; | ||
|
||
_CliCompletionMatcher( | ||
Map<String, String?> suggestions, { | ||
required this.cli, | ||
this.cursorIndex, | ||
}) : super( | ||
'Completes with the expected suggestions', | ||
'suggestions', | ||
completion(suggestions), | ||
); | ||
|
||
final int? cursorIndex; | ||
|
||
@override | ||
Object? featureValueOf(dynamic line) { | ||
if (line is! String) { | ||
throw ArgumentError.value(line, 'line', 'must be a String'); | ||
} | ||
|
||
return cli._runCompletionCommand(line, cursorIndex: cursorIndex); | ||
} | ||
} | ||
|
||
/// Simulate the shell behavior of completing a command line. | ||
Map<String, String> _prepareEnvForLineInput(String line, {int? cursorIndex}) { | ||
final cpoint = cursorIndex ?? line.length; | ||
var cword = 0; | ||
line.split(' ').fold(0, (value, element) { | ||
final total = value + 1 + element.length; | ||
if (total < cpoint) { | ||
cword++; | ||
return total; | ||
} | ||
return value; | ||
}); | ||
return { | ||
'COMP_LINE': line, | ||
'COMP_POINT': '$cpoint', | ||
'COMP_CWORD': '$cword', | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.