blob: dfb2f539f26ab1cecc53dde2e572fb4c31fa50b6 [file] [edit]
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:path/path.dart' as p;
import 'package:pub/src/platform_info.dart';
import 'package:source_span/source_span.dart';
import 'package:test/test.dart';
void main() {
test('overriding works', () async {
final originalOS = platform.operatingSystem;
final fakePlatform = PlatformInfo.override(
environment: {'FOO': 'BAR'},
executable: 'dart_fake',
isAndroid: false,
isFuchsia: false,
isIOS: false,
isLinux: false,
isMacOS: false,
isWindows: true,
lineTerminator: '\r\n',
operatingSystem: 'windows',
pathSeparator: '\\',
resolvedExecutable: 'C:\\bin\\dart_fake',
version: '3.0.0-fake',
script: Uri.file('C:\\bin\\dart_fake.dart'),
numberOfProcessors: 2,
);
await withPlatform(() async {
expect(platform.operatingSystem, 'windows');
expect(platform.isWindows, isTrue);
expect(platform.isLinux, isFalse);
expect(platform.environment['FOO'], 'BAR');
expect(platform.executable, 'dart_fake');
expect(platform.pathSeparator, '\\');
}, platform: fakePlatform);
expect(platform.operatingSystem, originalOS);
}, testOn: 'vm');
test('overriding works (also in browser)', () async {
final fakePlatform = PlatformInfo.override(
environment: {'FOO': 'BAR'},
executable: 'dart_fake',
isAndroid: false,
isFuchsia: false,
isIOS: false,
isLinux: false,
isMacOS: false,
isWindows: true,
lineTerminator: '\r\n',
operatingSystem: 'windows',
pathSeparator: '\\',
resolvedExecutable: 'C:\\bin\\dart_fake',
version: '3.0.0-fake',
script: Uri.file('C:\\bin\\dart_fake.dart'),
numberOfProcessors: 2,
);
await withPlatform(() async {
expect(platform.operatingSystem, 'windows');
expect(platform.isWindows, isTrue);
expect(platform.isLinux, isFalse);
expect(platform.environment['FOO'], 'BAR');
expect(platform.executable, 'dart_fake');
expect(platform.pathSeparator, '\\');
}, platform: fakePlatform);
});
test('Platform is not used outside platform_info.dart', () async {
// This test exists to ensure that we don't use Platform from dart:io
// unintentionally. We only want to use it in lib/src/platform_info.dart!
// Everywhere else we should rely on `platform` from here.
// This way, we can overrride the platform when we need to.
final allowListedFiles = [
'lib/src/platform_info.dart',
'test/platform_info_test.dart',
];
final root = p.normalize(p.absolute('.'));
final collection = AnalysisContextCollection(
includedPaths: [p.join(root, 'lib')],
);
for (final context in collection.contexts) {
for (final filePath in context.contextRoot.analyzedFiles()) {
if (!filePath.endsWith('.dart')) continue;
// Skip allow listed files
if (allowListedFiles.contains(p.relative(filePath, from: root))) {
continue;
}
final result = await context.currentSession.getResolvedUnit(filePath);
if (result is ResolvedUnitResult) {
SourceSpan? first;
result.unit.accept(
ForEachIdentifier((element) {
if (first == null &&
element.element?.name == 'Platform' &&
element.element?.library?.name == 'dart.io') {
first = SourceFile.fromString(
result.content,
url: filePath,
).span(element.offset, element.end);
}
}),
);
if (first != null) {
fail(
first!.message(
'Found Platform usage from dart:io, '
'use lib/src/platform_info.dart instead.',
),
);
}
}
}
}
}, testOn: 'vm && linux');
}
final class ForEachIdentifier extends GeneralizingAstVisitor<void> {
final void Function(Identifier element) _visitIdentifier;
ForEachIdentifier(this._visitIdentifier);
@override
void visitComment(Comment node) {
// Do not walk into comments! They are allowed to reference Platform!
}
@override
void visitIdentifier(Identifier element) {
_visitIdentifier(element);
super.visitIdentifier(element);
}
}