Skip to content

Windows version check in doctor #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions packages/flutter_tools/lib/src/doctor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
flutterRoot: () => Cache.flutterRoot!,
operatingSystemUtils: globals.os,
),
if (platform.isWindows) WindowsVersionValidator(
processManager: globals.processManager,
),
if (platform.isWindows)
WindowsVersionValidator(
processManager: globals.processManager,
),
if (androidWorkflow!.appliesToHostPlatform)
GroupedValidator(<DoctorValidator>[androidValidator!, androidLicenseValidator!]),
if (globals.iosWorkflow!.appliesToHostPlatform || macOSWorkflow.appliesToHostPlatform)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,30 @@ import 'package:process/process.dart';
import '../base/io.dart';
import '../doctor_validator.dart';

const List<String> unsupportedVersions = <String>[
/// Flutter only supports development on Windows host machines version 10 and greater.
const List<String> kUnsupportedVersions = <String>[
'6',
'7',
'8',
];

/// Validator to be run with `flutter doctor` to check
/// Windows host machines if they are running supported versions.
/// Regex pattern for identifying line from systeminfo stdout with windows version
/// (ie. 10.5.4123)
const String kWindowsOSVersionSemVerPattern =
r'^(OS Version:\s*)([0-9]+\.[0-9]+\.[0-9]+)(.*)$';

/// Validator for supported Windows host machine operating system version.
class WindowsVersionValidator extends DoctorValidator {
const WindowsVersionValidator({required ProcessManager processManager})
: _processManager = processManager,
super('Windows Version');

final ProcessManager _processManager;

/// Provide a literal string as the Regex pattern
/// and a string to validate and get a boolean determining
/// if the string has at least one match
static Iterable<RegExpMatch> validateString(String pattern, String str,
{bool multiLine = true}) {
final RegExp regex = RegExp(
pattern,
multiLine: multiLine,
);

return regex.allMatches(str);
}

@override
Future<ValidationResult> validate() async {
final ProcessResult result;
try {
result = await _processManager.run(<String>['systeminfo']);
} on ProcessException {
return const ValidationResult(
ValidationType.missing,
<ValidationMessage>[],
statusInfo:
'Unable to run Windows version check using built-in `systeminfo`',
);
}
final ProcessResult result =
await _processManager.run(<String>['systeminfo']);

if (result.exitCode != 0) {
return const ValidationResult(
Expand All @@ -59,18 +42,16 @@ class WindowsVersionValidator extends DoctorValidator {

final String resultStdout = result.stdout as String;

// Regular expression pattern for identifying
// semantic versioned strings
// (ie. 10.5.4123)
final Iterable<RegExpMatch> matches = validateString(
r'^(OS Version:\s*)([0-9]+\.[0-9]+\.[0-9]+)(.*)$', resultStdout);
final RegExp regex =
RegExp(kWindowsOSVersionSemVerPattern, multiLine: true);
final Iterable<RegExpMatch> matches = regex.allMatches(resultStdout);

// Use the string split method to extract the major version
// and check against the [unsupportedVersions] list
// and check against the [kUnsupportedVersions] list
final ValidationType windowsVersionStatus;
String statusInfo;
final String statusInfo;
if (matches.length == 1 &&
!unsupportedVersions
!kUnsupportedVersions
.contains(matches.elementAt(0).group(2)?.split('.').elementAt(0))) {
windowsVersionStatus = ValidationType.installed;
statusInfo = 'Installed version of Windows is version 10 or higher';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ const ValidationResult invalidWindowsValidationResult = ValidationResult(
statusInfo: 'Unable to confirm if installed Windows version is 10 or greater',
);

/// Expected return from a nonzero exitcode when
/// running systeminfo
const ValidationResult invalidExitCodeValidationResult = ValidationResult(
ValidationType.missing,
<ValidationMessage>[],
statusInfo: 'Exit status from running `systeminfo` was unsuccessful',
);

void main() {
testWithoutContext('Successfully running windows version check on windows 10',
() async {
Expand Down Expand Up @@ -186,9 +194,26 @@ void main() {
reason: 'The ValidationResult statusInfo messages should be the same');
});

testWithoutContext(
'Running into an nonzero exit code from systeminfo command', () async {
final WindowsVersionValidator windowsVersionValidator =
WindowsVersionValidator(
processManager: FakeProcessManager.list(
<FakeCommand>[
const FakeCommand(command: <String>['systeminfo'], exitCode: 1),
],
),
);

final ValidationResult result = await windowsVersionValidator.validate();

expect(result.type, invalidExitCodeValidationResult.type,
reason: 'The ValidationResult type should be the same (missing)');
expect(result.statusInfo, invalidExitCodeValidationResult.statusInfo,
reason: 'The ValidationResult statusInfo messages should be the same');
});

testWithoutContext('Unit testing on a regex pattern validator', () async {
const String regexPattern =
r'^(OS Version:\s*)([0-9]+\.[0-9]+\.[0-9]+)(.*)$';
const String testStr = r'''
OS Version: 10.0.19044 N/A Build 19044
OSz Version: 10.0.19044 N/A Build 19044
Expand All @@ -200,8 +225,9 @@ OS Version: 10.0.19044 N/A Build 19044
OS Version: .0.19044 N/A Build 19044
''';

final Iterable<RegExpMatch> matches =
WindowsVersionValidator.validateString(regexPattern, testStr);
final RegExp regex =
RegExp(kWindowsOSVersionSemVerPattern, multiLine: true);
final Iterable<RegExpMatch> matches = regex.allMatches(testStr);

expect(matches.length, 2,
reason: 'There should be only two matches for the pattern provided');
Expand Down