Skip to content

Allow specifying an explicit location for test/groups #2481

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 14 commits into from
Apr 28, 2025
Merged
7 changes: 0 additions & 7 deletions pkgs/test/test/runner/line_and_col_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,6 @@ void main() {

test('additionally selects groups with a matching custom location',
() async {
// TODO(dantup): This fails because we don't ever look at a groups
// location.. instead, we only look at tests. The reason we can
// normally run groups by line/col is because they just happen to be
// in the stack trace for the test() call too.
//
// So maybe we need to look up the tree to match location (in
// Runner._loadSuites() filter)?
await d.dir('test').create();
var testFileUri = Uri.file(d.file('test/aaa_test.dart').io.path);
var notTestFileUri = Uri.file(d.file('test/bbb.dart').io.path);
Expand Down
12 changes: 11 additions & 1 deletion pkgs/test_api/lib/src/backend/declarer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -364,12 +364,22 @@ class Declarer {
return entry;
}).toList();

return Group(_name ?? '', entries,
var result = Group(_name ?? '', entries,
metadata: _metadata,
trace: _trace,
location: _location,
setUpAll: _setUpAll,
tearDownAll: _tearDownAll);

// Now we have created the group, we can set it as the parent for all
// child entries.
for (var entry in result.entries) {
entry.parent = result;
}
result.setUpAll?.parent = result;
result.tearDownAll?.parent = result;

return result;
}

/// Throws a [StateError] if [build] has been called.
Expand Down
3 changes: 3 additions & 0 deletions pkgs/test_api/lib/src/backend/group.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class Group implements GroupEntry {
@override
final String name;

@override
Group? parent;

@override
final Metadata metadata;

Expand Down
10 changes: 7 additions & 3 deletions pkgs/test_api/lib/src/backend/group_entry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
// 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.

/// @docImport 'group.dart';
library;

import 'package:stack_trace/stack_trace.dart';

import 'group.dart';
import 'metadata.dart';
import 'suite_platform.dart';
import 'test.dart';
Expand All @@ -20,6 +18,12 @@ abstract class GroupEntry {
/// This will be empty for the root group.
String get name;

/// The parent of this entry.
///
/// This field is set during during building in the Declarer and also during
/// deserialization of the parent.
Group? parent;

/// The metadata for the entry, including the metadata from any containing
/// [Group]s.
Metadata get metadata;
Expand Down
3 changes: 3 additions & 0 deletions pkgs/test_api/lib/src/backend/test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ abstract class Test implements GroupEntry {
@override
String get name;

@override
Group? parent;

@override
Metadata get metadata;

Expand Down
3 changes: 3 additions & 0 deletions pkgs/test_api/lib/src/backend/test_location.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class TestLocation {

/// Serializes [this] into a JSON-safe object that can be deserialized using
/// [TestLocation.deserialize].
///
/// This method is also used to provide the location in the JSON reporter when
/// a custom location is provided for the test.
Map<String, dynamic> serialize() {
return {
'url': uri.toString(),
Expand Down
21 changes: 13 additions & 8 deletions pkgs/test_core/lib/src/runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,7 @@ class Runner {
if (line == null && col == null) return true;

var trace = test.trace;
var location = test.location;
if (trace == null && location == null) {
if (trace == null && test.location == null) {
throw StateError(
'Cannot filter by line/column for this test suite, no stack'
'trace or location available.');
Expand Down Expand Up @@ -351,13 +350,19 @@ class Runner {
return true;
}

// First check if we're a match for the overridden location.
if (location != null) {
if ((line == null || location.line == line) &&
(col == null || location.column == col) &&
matchesUri(location.uri)) {
return true;
// First check if we're a match for the overridden location for this
// item or any parents.
var current = test as GroupEntry?;
while (current != null) {
var location = current.location;
if (location != null) {
if ((line == null || location.line == line) &&
(col == null || location.column == col) &&
matchesUri(location.uri)) {
return true;
}
}
current = current.parent;
}

/// Helper to check if [frame] matches the suite path, line and col.
Expand Down
3 changes: 2 additions & 1 deletion pkgs/test_core/lib/src/runner/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,8 @@ class Engine {
Future _runSkippedTest(LiveSuiteController suiteController, Test test,
List<Group> parents) async {
await _onUnpaused;
var skipped = LocalTest(test.name, test.metadata, () {}, trace: test.trace);
var skipped = LocalTest(test.name, test.metadata, () {},
trace: test.trace, location: test.location);

late LiveTestController controller;
controller =
Expand Down
24 changes: 17 additions & 7 deletions pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,28 @@ class _Deserializer {
Map map => TestLocation.deserialize(map),
_ => null,
};
return Group(
group['name'] as String,
(group['entries'] as List).map((entry) {
var map = entry as Map;
if (map['type'] == 'group') return deserializeGroup(map);
return _deserializeTest(map)!;
}),
var entries = (group['entries'] as List).map((entry) {
var map = entry as Map;
if (map['type'] == 'group') return deserializeGroup(map);
return _deserializeTest(map)!;
}).toList();

var result = Group(group['name'] as String, entries,
metadata: metadata,
trace: trace,
location: location,
setUpAll: _deserializeTest(group['setUpAll'] as Map?),
tearDownAll: _deserializeTest(group['tearDownAll'] as Map?));

// Now we have created the group, we can set it as the parent for all
// child entries.
for (var entry in result.entries) {
entry.parent = result;
}
result.setUpAll?.parent = result;
result.tearDownAll?.parent = result;

return result;
}

/// Deserializes [test] into a concrete [Test] class.
Expand Down
6 changes: 1 addition & 5 deletions pkgs/test_core/lib/src/runner/reporter/json.dart
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,7 @@ class JsonReporter implements Reporter {
String suitePath) {
// If this test has a location override, always use that.
if (location != null) {
return {
'line': location.line,
'column': location.column,
'url': location.uri.toString()
};
return location.serialize();
}

var absoluteSuitePath = p.canonicalize(p.absolute(suitePath));
Expand Down
6 changes: 5 additions & 1 deletion pkgs/test_core/lib/src/runner/runner_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,11 @@ class RunnerTest extends Test {
@override
Test? forPlatform(SuitePlatform platform) {
if (!metadata.testOn.evaluate(platform)) return null;
return RunnerTest(
var result = RunnerTest(
name, metadata.forPlatform(platform), trace, location, _channel);
// Parents are copied after construction, since usually we build
// bottom-up.
result.parent = parent;
return result;
}
}