LCOV - code coverage report
Current view: top level - test_core-0.4.9/lib/src/runner - suite.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 120 0.0 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
       2             : // for details. All rights reserved. Use of this source code is governed by a
       3             : // BSD-style license that can be found in the LICENSE file.
       4             : 
       5             : import 'package:boolean_selector/boolean_selector.dart';
       6             : import 'package:collection/collection.dart';
       7             : import 'package:source_span/source_span.dart';
       8             : import 'package:test_api/scaffolding.dart' // ignore: deprecated_member_use
       9             :     show
      10             :         Timeout;
      11             : import 'package:test_api/src/backend/metadata.dart'; // ignore: implementation_imports
      12             : import 'package:test_api/src/backend/platform_selector.dart'; // ignore: implementation_imports
      13             : import 'package:test_api/src/backend/runtime.dart'; // ignore: implementation_imports
      14             : import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports
      15             : 
      16             : import 'runtime_selection.dart';
      17             : 
      18             : /// Suite-level configuration.
      19             : ///
      20             : /// This tracks configuration that can differ from suite to suite.
      21             : class SuiteConfiguration {
      22             :   /// Empty configuration with only default values.
      23             :   ///
      24             :   /// Using this is slightly more efficient than manually constructing a new
      25             :   /// configuration with no arguments.
      26           0 :   static final empty = SuiteConfiguration._(
      27             :       allowDuplicateTestNames: null,
      28             :       allowTestRandomization: null,
      29             :       jsTrace: null,
      30             :       runSkipped: null,
      31             :       dart2jsArgs: null,
      32             :       precompiledPath: null,
      33             :       patterns: null,
      34             :       runtimes: null,
      35             :       includeTags: null,
      36             :       excludeTags: null,
      37             :       tags: null,
      38             :       onPlatform: null,
      39             :       metadata: null,
      40             :       line: null,
      41             :       col: null);
      42             : 
      43             :   /// Whether or not duplicate test (or group) names are allowed within the same
      44             :   /// test suite.
      45             :   //
      46             :   // TODO: Change the default https://github.com/dart-lang/test/issues/1571
      47           0 :   bool get allowDuplicateTestNames => _allowDuplicateTestNames ?? true;
      48             :   final bool? _allowDuplicateTestNames;
      49             : 
      50             :   /// Whether test randomization should be allowed for this test.
      51           0 :   bool get allowTestRandomization => _allowTestRandomization ?? true;
      52             :   final bool? _allowTestRandomization;
      53             : 
      54             :   /// Whether JavaScript stack traces should be left as-is or converted to
      55             :   /// Dart-like traces.
      56           0 :   bool get jsTrace => _jsTrace ?? false;
      57             :   final bool? _jsTrace;
      58             : 
      59             :   /// Whether skipped tests should be run.
      60           0 :   bool get runSkipped => _runSkipped ?? false;
      61             :   final bool? _runSkipped;
      62             : 
      63             :   /// The path to a mirror of this package containing HTML that points to
      64             :   /// precompiled JS.
      65             :   ///
      66             :   /// This is used by the internal Google test runner so that test compilation
      67             :   /// can more effectively make use of Google's build tools.
      68             :   final String? precompiledPath;
      69             : 
      70             :   /// Additional arguments to pass to dart2js.
      71             :   ///
      72             :   /// Note that this if multiple suites run the same JavaScript on different
      73             :   /// runtimes, and they have different [dart2jsArgs], only one (undefined)
      74             :   /// suite's arguments will be used.
      75             :   final List<String> dart2jsArgs;
      76             : 
      77             :   /// The patterns to match against test names to decide which to run.
      78             :   ///
      79             :   /// All patterns must match in order for a test to be run.
      80             :   ///
      81             :   /// If empty, all tests should be run.
      82             :   final Set<Pattern> patterns;
      83             : 
      84             :   /// The set of runtimes on which to run tests.
      85           0 :   List<String> get runtimes => _runtimes == null
      86             :       ? const ['vm']
      87           0 :       : List.unmodifiable(_runtimes!.map((runtime) => runtime.name));
      88             :   final List<RuntimeSelection>? _runtimes;
      89             : 
      90             :   /// Only run tests whose tags match this selector.
      91             :   ///
      92             :   /// When [merge]d, this is intersected with the other configuration's included
      93             :   /// tags.
      94             :   final BooleanSelector includeTags;
      95             : 
      96             :   /// Do not run tests whose tags match this selector.
      97             :   ///
      98             :   /// When [merge]d, this is unioned with the other configuration's
      99             :   /// excluded tags.
     100             :   final BooleanSelector excludeTags;
     101             : 
     102             :   /// Configuration for particular tags.
     103             :   ///
     104             :   /// The keys are tag selectors, and the values are configurations for tests
     105             :   /// whose tags match those selectors.
     106             :   final Map<BooleanSelector, SuiteConfiguration> tags;
     107             : 
     108             :   /// Configuration for particular platforms.
     109             :   ///
     110             :   /// The keys are platform selectors, and the values are configurations for
     111             :   /// those platforms. These configuration should only contain test-level
     112             :   /// configuration fields, but that isn't enforced.
     113             :   final Map<PlatformSelector, SuiteConfiguration> onPlatform;
     114             : 
     115             :   /// The global test metadata derived from this configuration.
     116           0 :   Metadata get metadata {
     117           0 :     if (tags.isEmpty && onPlatform.isEmpty) return _metadata;
     118           0 :     return _metadata.change(
     119           0 :         forTag: tags.map((key, config) => MapEntry(key, config.metadata)),
     120             :         onPlatform:
     121           0 :             onPlatform.map((key, config) => MapEntry(key, config.metadata)));
     122             :   }
     123             : 
     124             :   final Metadata _metadata;
     125             : 
     126             :   /// The set of tags that have been declared in any way in this configuration.
     127           0 :   Set<String> get knownTags => _knownTags ??= UnmodifiableSetView({
     128           0 :         ...includeTags.variables,
     129           0 :         ...excludeTags.variables,
     130           0 :         ..._metadata.tags,
     131           0 :         for (var selector in tags.keys) ...selector.variables,
     132           0 :         for (var configuration in tags.values) ...configuration.knownTags,
     133           0 :         for (var configuration in onPlatform.values) ...configuration.knownTags,
     134             :       });
     135             :   Set<String>? _knownTags;
     136             : 
     137             :   /// Only run tests that originate from this line in a test file.
     138             :   final int? line;
     139             : 
     140             :   /// Only run tests that original from this column in a test file.
     141             :   final int? col;
     142             : 
     143           0 :   factory SuiteConfiguration(
     144             :       {required bool? allowDuplicateTestNames,
     145             :       required bool? allowTestRandomization,
     146             :       required bool? jsTrace,
     147             :       required bool? runSkipped,
     148             :       required Iterable<String>? dart2jsArgs,
     149             :       required String? precompiledPath,
     150             :       required Iterable<Pattern>? patterns,
     151             :       required Iterable<RuntimeSelection>? runtimes,
     152             :       required BooleanSelector? includeTags,
     153             :       required BooleanSelector? excludeTags,
     154             :       required Map<BooleanSelector, SuiteConfiguration>? tags,
     155             :       required Map<PlatformSelector, SuiteConfiguration>? onPlatform,
     156             :       required int? line,
     157             :       required int? col,
     158             : 
     159             :       // Test-level configuration
     160             :       required Timeout? timeout,
     161             :       required bool? verboseTrace,
     162             :       required bool? chainStackTraces,
     163             :       required bool? skip,
     164             :       required int? retry,
     165             :       required String? skipReason,
     166             :       required PlatformSelector? testOn,
     167             :       required Iterable<String>? addTags}) {
     168           0 :     var config = SuiteConfiguration._(
     169             :         allowDuplicateTestNames: allowDuplicateTestNames,
     170             :         allowTestRandomization: allowTestRandomization,
     171             :         jsTrace: jsTrace,
     172             :         runSkipped: runSkipped,
     173             :         dart2jsArgs: dart2jsArgs,
     174             :         precompiledPath: precompiledPath,
     175             :         patterns: patterns,
     176             :         runtimes: runtimes,
     177             :         includeTags: includeTags,
     178             :         excludeTags: excludeTags,
     179             :         tags: tags,
     180             :         onPlatform: onPlatform,
     181             :         line: line,
     182             :         col: col,
     183           0 :         metadata: Metadata(
     184             :             timeout: timeout,
     185             :             verboseTrace: verboseTrace,
     186             :             chainStackTraces: chainStackTraces,
     187             :             skip: skip,
     188             :             retry: retry,
     189             :             skipReason: skipReason,
     190             :             testOn: testOn,
     191             :             tags: addTags));
     192           0 :     return config._resolveTags();
     193             :   }
     194             : 
     195             :   /// A constructor that doesn't require all of its options to be passed.
     196             :   ///
     197             :   /// This should only be used in situations where you really only want to
     198             :   /// configure a specific restricted set of options.
     199           0 :   factory SuiteConfiguration._unsafe(
     200             :           {bool? allowDuplicateTestNames,
     201             :           bool? allowTestRandomization,
     202             :           bool? jsTrace,
     203             :           bool? runSkipped,
     204             :           Iterable<String>? dart2jsArgs,
     205             :           String? precompiledPath,
     206             :           Iterable<Pattern>? patterns,
     207             :           Iterable<RuntimeSelection>? runtimes,
     208             :           BooleanSelector? includeTags,
     209             :           BooleanSelector? excludeTags,
     210             :           Map<BooleanSelector, SuiteConfiguration>? tags,
     211             :           Map<PlatformSelector, SuiteConfiguration>? onPlatform,
     212             :           int? line,
     213             :           int? col,
     214             : 
     215             :           // Test-level configuration
     216             :           Timeout? timeout,
     217             :           bool? verboseTrace,
     218             :           bool? chainStackTraces,
     219             :           bool? skip,
     220             :           int? retry,
     221             :           String? skipReason,
     222             :           PlatformSelector? testOn,
     223             :           Iterable<String>? addTags}) =>
     224           0 :       SuiteConfiguration(
     225             :           allowDuplicateTestNames: allowDuplicateTestNames,
     226             :           allowTestRandomization: allowTestRandomization,
     227             :           jsTrace: jsTrace,
     228             :           runSkipped: runSkipped,
     229             :           dart2jsArgs: dart2jsArgs,
     230             :           precompiledPath: precompiledPath,
     231             :           patterns: patterns,
     232             :           runtimes: runtimes,
     233             :           includeTags: includeTags,
     234             :           excludeTags: excludeTags,
     235             :           tags: tags,
     236             :           onPlatform: onPlatform,
     237             :           line: line,
     238             :           col: col,
     239             :           timeout: timeout,
     240             :           verboseTrace: verboseTrace,
     241             :           chainStackTraces: chainStackTraces,
     242             :           skip: skip,
     243             :           retry: retry,
     244             :           skipReason: skipReason,
     245             :           testOn: testOn,
     246             :           addTags: addTags);
     247             : 
     248             :   /// A specialized constructor for only configuring the runtimes.
     249           0 :   factory SuiteConfiguration.runtimes(Iterable<RuntimeSelection> runtimes) =>
     250           0 :       SuiteConfiguration._unsafe(runtimes: runtimes);
     251             : 
     252             :   /// A specialized constructor for only configuring runSkipped.
     253           0 :   factory SuiteConfiguration.runSkipped(bool runSkipped) =>
     254           0 :       SuiteConfiguration._unsafe(runSkipped: runSkipped);
     255             : 
     256             :   /// A specialized constructor for only configuring the timeout.
     257           0 :   factory SuiteConfiguration.timeout(Timeout timeout) =>
     258           0 :       SuiteConfiguration._unsafe(timeout: timeout);
     259             : 
     260             :   /// Creates new SuiteConfiguration.
     261             :   ///
     262             :   /// Unlike [new SuiteConfiguration], this assumes [tags] is already
     263             :   /// resolved.
     264           0 :   SuiteConfiguration._(
     265             :       {required bool? allowDuplicateTestNames,
     266             :       required bool? allowTestRandomization,
     267             :       required bool? jsTrace,
     268             :       required bool? runSkipped,
     269             :       required Iterable<String>? dart2jsArgs,
     270             :       required this.precompiledPath,
     271             :       required Iterable<Pattern>? patterns,
     272             :       required Iterable<RuntimeSelection>? runtimes,
     273             :       required BooleanSelector? includeTags,
     274             :       required BooleanSelector? excludeTags,
     275             :       required Map<BooleanSelector, SuiteConfiguration>? tags,
     276             :       required Map<PlatformSelector, SuiteConfiguration>? onPlatform,
     277             :       required Metadata? metadata,
     278             :       required this.line,
     279             :       required this.col})
     280             :       : _allowDuplicateTestNames = allowDuplicateTestNames,
     281             :         _allowTestRandomization = allowTestRandomization,
     282             :         _jsTrace = jsTrace,
     283             :         _runSkipped = runSkipped,
     284           0 :         dart2jsArgs = _list(dart2jsArgs) ?? const [],
     285           0 :         patterns = UnmodifiableSetView(patterns?.toSet() ?? {}),
     286           0 :         _runtimes = _list(runtimes),
     287             :         includeTags = includeTags ?? BooleanSelector.all,
     288             :         excludeTags = excludeTags ?? BooleanSelector.none,
     289           0 :         tags = _map(tags),
     290           0 :         onPlatform = _map(onPlatform),
     291           0 :         _metadata = metadata ?? Metadata.empty;
     292             : 
     293             :   /// Creates a new [SuiteConfiguration] that takes its configuration from
     294             :   /// [metadata].
     295           0 :   factory SuiteConfiguration.fromMetadata(Metadata metadata) =>
     296           0 :       SuiteConfiguration._(
     297           0 :         tags: metadata.forTag.map((key, child) =>
     298           0 :             MapEntry(key, SuiteConfiguration.fromMetadata(child))),
     299           0 :         onPlatform: metadata.onPlatform.map((key, child) =>
     300           0 :             MapEntry(key, SuiteConfiguration.fromMetadata(child))),
     301           0 :         metadata: metadata.change(forTag: {}, onPlatform: {}),
     302             :         allowDuplicateTestNames: null,
     303             :         allowTestRandomization: null,
     304             :         jsTrace: null,
     305             :         runSkipped: null,
     306             :         dart2jsArgs: null,
     307             :         precompiledPath: null,
     308             :         patterns: null,
     309             :         runtimes: null,
     310             :         includeTags: null,
     311             :         excludeTags: null,
     312             :         line: null,
     313             :         col: null,
     314             :       );
     315             : 
     316             :   /// Returns an unmodifiable copy of [input].
     317             :   ///
     318             :   /// If [input] is `null` or empty, this returns `null`.
     319           0 :   static List<T>? _list<T>(Iterable<T>? input) {
     320             :     if (input == null) return null;
     321           0 :     var list = List<T>.unmodifiable(input);
     322           0 :     if (list.isEmpty) return null;
     323             :     return list;
     324             :   }
     325             : 
     326             :   /// Returns an unmodifiable copy of [input] or an empty unmodifiable map.
     327           0 :   static Map<K, V> _map<K, V>(Map<K, V>? input) {
     328           0 :     if (input == null || input.isEmpty) return const <Never, Never>{};
     329           0 :     return Map.unmodifiable(input);
     330             :   }
     331             : 
     332             :   /// Merges this with [other].
     333             :   ///
     334             :   /// For most fields, if both configurations have values set, [other]'s value
     335             :   /// takes precedence. However, certain fields are merged together instead.
     336             :   /// This is indicated in those fields' documentation.
     337           0 :   SuiteConfiguration merge(SuiteConfiguration other) {
     338           0 :     if (this == SuiteConfiguration.empty) return other;
     339           0 :     if (other == SuiteConfiguration.empty) return this;
     340             : 
     341           0 :     var config = SuiteConfiguration._(
     342             :         allowDuplicateTestNames:
     343           0 :             other._allowDuplicateTestNames ?? _allowDuplicateTestNames,
     344             :         allowTestRandomization:
     345           0 :             other._allowTestRandomization ?? _allowTestRandomization,
     346           0 :         jsTrace: other._jsTrace ?? _jsTrace,
     347           0 :         runSkipped: other._runSkipped ?? _runSkipped,
     348           0 :         dart2jsArgs: dart2jsArgs.toList()..addAll(other.dart2jsArgs),
     349           0 :         precompiledPath: other.precompiledPath ?? precompiledPath,
     350           0 :         patterns: patterns.union(other.patterns),
     351           0 :         runtimes: other._runtimes ?? _runtimes,
     352           0 :         includeTags: includeTags.intersection(other.includeTags),
     353           0 :         excludeTags: excludeTags.union(other.excludeTags),
     354           0 :         tags: _mergeConfigMaps(tags, other.tags),
     355           0 :         onPlatform: _mergeConfigMaps(onPlatform, other.onPlatform),
     356           0 :         line: other.line ?? line,
     357           0 :         col: other.col ?? col,
     358           0 :         metadata: metadata.merge(other.metadata));
     359           0 :     return config._resolveTags();
     360             :   }
     361             : 
     362             :   /// Returns a copy of this configuration with the given fields updated.
     363             :   ///
     364             :   /// Note that unlike [merge], this has no merging behavior—the old value is
     365             :   /// always replaced by the new one.
     366           0 :   SuiteConfiguration change(
     367             :       {bool? allowDuplicateTestNames,
     368             :       bool? allowTestRandomization,
     369             :       bool? jsTrace,
     370             :       bool? runSkipped,
     371             :       Iterable<String>? dart2jsArgs,
     372             :       String? precompiledPath,
     373             :       Iterable<Pattern>? patterns,
     374             :       Iterable<RuntimeSelection>? runtimes,
     375             :       BooleanSelector? includeTags,
     376             :       BooleanSelector? excludeTags,
     377             :       Map<BooleanSelector, SuiteConfiguration>? tags,
     378             :       Map<PlatformSelector, SuiteConfiguration>? onPlatform,
     379             :       int? line,
     380             :       int? col,
     381             : 
     382             :       // Test-level configuration
     383             :       Timeout? timeout,
     384             :       bool? verboseTrace,
     385             :       bool? chainStackTraces,
     386             :       bool? skip,
     387             :       int? retry,
     388             :       String? skipReason,
     389             :       PlatformSelector? testOn,
     390             :       Iterable<String>? addTags}) {
     391           0 :     var config = SuiteConfiguration._(
     392             :         allowDuplicateTestNames:
     393           0 :             allowDuplicateTestNames ?? _allowDuplicateTestNames,
     394             :         allowTestRandomization:
     395           0 :             allowTestRandomization ?? _allowTestRandomization,
     396           0 :         jsTrace: jsTrace ?? _jsTrace,
     397           0 :         runSkipped: runSkipped ?? _runSkipped,
     398           0 :         dart2jsArgs: dart2jsArgs?.toList() ?? this.dart2jsArgs,
     399           0 :         precompiledPath: precompiledPath ?? this.precompiledPath,
     400           0 :         patterns: patterns ?? this.patterns,
     401           0 :         runtimes: runtimes ?? _runtimes,
     402           0 :         includeTags: includeTags ?? this.includeTags,
     403           0 :         excludeTags: excludeTags ?? this.excludeTags,
     404           0 :         tags: tags ?? this.tags,
     405           0 :         onPlatform: onPlatform ?? this.onPlatform,
     406           0 :         line: line ?? this.line,
     407           0 :         col: col ?? this.col,
     408           0 :         metadata: _metadata.change(
     409             :             timeout: timeout,
     410             :             verboseTrace: verboseTrace,
     411             :             chainStackTraces: chainStackTraces,
     412             :             skip: skip,
     413             :             retry: retry,
     414             :             skipReason: skipReason,
     415             :             testOn: testOn,
     416           0 :             tags: addTags?.toSet()));
     417           0 :     return config._resolveTags();
     418             :   }
     419             : 
     420             :   /// Throws a [FormatException] if this refers to any undefined runtimes.
     421           0 :   void validateRuntimes(List<Runtime> allRuntimes) {
     422             :     var validVariables =
     423           0 :         allRuntimes.map((runtime) => runtime.identifier).toSet();
     424           0 :     _metadata.validatePlatformSelectors(validVariables);
     425             : 
     426           0 :     var runtimes = _runtimes;
     427             :     if (runtimes != null) {
     428           0 :       for (var selection in runtimes) {
     429             :         if (!allRuntimes
     430           0 :             .any((runtime) => runtime.identifier == selection.name)) {
     431           0 :           if (selection.span != null) {
     432           0 :             throw SourceSpanFormatException(
     433           0 :                 'Unknown platform "${selection.name}".', selection.span);
     434             :           } else {
     435           0 :             throw FormatException('Unknown platform "${selection.name}".');
     436             :           }
     437             :         }
     438             :       }
     439             :     }
     440             : 
     441           0 :     onPlatform.forEach((selector, config) {
     442           0 :       selector.validate(validVariables);
     443           0 :       config.validateRuntimes(allRuntimes);
     444             :     });
     445             :   }
     446             : 
     447             :   /// Returns a copy of this with all platform-specific configuration from
     448             :   /// [onPlatform] resolved.
     449           0 :   SuiteConfiguration forPlatform(SuitePlatform platform) {
     450           0 :     if (onPlatform.isEmpty) return this;
     451             : 
     452             :     var config = this;
     453           0 :     onPlatform.forEach((platformSelector, platformConfig) {
     454           0 :       if (!platformSelector.evaluate(platform)) return;
     455           0 :       config = config.merge(platformConfig);
     456             :     });
     457           0 :     return config.change(onPlatform: {});
     458             :   }
     459             : 
     460             :   /// Merges two maps whose values are [SuiteConfiguration]s.
     461             :   ///
     462             :   /// Any overlapping keys in the maps have their configurations merged in the
     463             :   /// returned map.
     464           0 :   Map<T, SuiteConfiguration> _mergeConfigMaps<T>(
     465             :           Map<T, SuiteConfiguration> map1, Map<T, SuiteConfiguration> map2) =>
     466           0 :       mergeMaps(map1, map2,
     467           0 :           value: (config1, config2) => config1.merge(config2));
     468             : 
     469           0 :   SuiteConfiguration _resolveTags() {
     470             :     // If there's no tag-specific configuration, or if none of it applies, just
     471             :     // return the configuration as-is.
     472           0 :     if (_metadata.tags.isEmpty || tags.isEmpty) return this;
     473             : 
     474             :     // Otherwise, resolve the tag-specific components.
     475           0 :     var newTags = Map<BooleanSelector, SuiteConfiguration>.from(tags);
     476           0 :     var merged = tags.keys.fold(empty, (SuiteConfiguration merged, selector) {
     477           0 :       if (!selector.evaluate(_metadata.tags.contains)) return merged;
     478           0 :       return merged.merge(newTags.remove(selector)!);
     479             :     });
     480             : 
     481           0 :     if (merged == empty) return this;
     482           0 :     return change(tags: newTags).merge(merged);
     483             :   }
     484             : }

Generated by: LCOV version 1.14