diff --git a/dwds/test/build_daemon_breakpoint_test.dart b/dwds/test/build_daemon_breakpoint_test.dart index 8115a33bb..14a7df87e 100644 --- a/dwds/test/build_daemon_breakpoint_test.dart +++ b/dwds/test/build_daemon_breakpoint_test.dart @@ -15,8 +15,8 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import 'fixtures/context.dart'; final context = TestContext( - directory: p.join('..', 'fixtures', '_testPackage'), - entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), + directory: p.join('..', 'fixtures', '_testPackageSound'), + entry: p.join('..', 'fixtures', '_testPackageSound', 'web', 'main.dart'), path: 'index.html', pathToServe: 'web'); diff --git a/dwds/test/build_daemon_callstack_test.dart b/dwds/test/build_daemon_callstack_test.dart index f03c059b3..2ccb9f1ae 100644 --- a/dwds/test/build_daemon_callstack_test.dart +++ b/dwds/test/build_daemon_callstack_test.dart @@ -14,19 +14,24 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import 'fixtures/context.dart'; import 'fixtures/logging.dart'; +import 'utils/version_compatibility.dart'; class TestSetup { static final contextUnsound = TestContext( - directory: p.join('..', 'fixtures', '_testPackage'), - entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); + directory: p.join('..', 'fixtures', '_testPackage'), + entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web', + nullSafety: NullSafety.weak, + ); static final contextSound = TestContext( - directory: p.join('..', 'fixtures', '_testPackageSound'), - entry: p.join('..', 'fixtures', '_testPackageSound', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); + directory: p.join('..', 'fixtures', '_testPackageSound'), + entry: p.join('..', 'fixtures', '_testPackageSound', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web', + nullSafety: NullSafety.sound, + ); TestContext context; @@ -40,270 +45,288 @@ class TestSetup { } void main() { - group('shared context |', () { - // Enable verbose logging for debugging. - final debug = false; - - for (var nullSafety in NullSafety.values) { - final soundNullSafety = nullSafety == NullSafety.sound; - final setup = soundNullSafety ? TestSetup.sound() : TestSetup.unsound(); - final context = setup.context; - - group('${nullSafety.name} null safety |', () { - setUpAll(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - compilationMode: CompilationMode.buildDaemon, - nullSafety: nullSafety, - enableExpressionEvaluation: true, - verboseCompiler: debug, - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - group('callStack |', () { - late ChromeProxyService service; - VM vm; - late Isolate isolate; - ScriptList scripts; - late ScriptRef mainScript; - late ScriptRef testLibraryScript; - late Stream stream; - - setUp(() async { - setCurrentLogWriter(debug: debug); - service = setup.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - scripts = await service.getScripts(isolate.id!); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - final testPackage = - soundNullSafety ? '_test_package_sound' : '_test_package'; - - mainScript = scripts.scripts! - .firstWhere((each) => each.uri!.contains('main.dart')); - testLibraryScript = scripts.scripts!.firstWhere((each) => - each.uri!.contains('package:$testPackage/test_library.dart')); - }); - - tearDown(() async { - await service.resume(isolate.id!); - }); - - Future onBreakPoint(BreakpointTestData breakpoint, - Future Function() body) async { - Breakpoint? bp; - try { - final bpId = breakpoint.bpId; - final script = breakpoint.script; - final line = - await context.findBreakpointLine(bpId, isolate.id!, script); - bp = await setup.service - .addBreakpointWithScriptUri(isolate.id!, script.uri!, line); - - expect(bp, isNotNull); - expect(bp.location, _matchBpLocation(script, line, 0)); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - await body(); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await setup.service.removeBreakpoint(isolate.id!, bp.id!); - } - } - } - - Future testCallStack(List breakpoints, - {int frameIndex = 1}) async { - // Find lines the breakpoints are located on. - final lines = await Future.wait(breakpoints.map((frame) => context - .findBreakpointLine(frame.bpId, isolate.id!, frame.script))); - - // Get current stack. - final stack = await service.getStack(isolate.id!); - - // Verify the stack is correct. - expect(stack.frames!.length, greaterThanOrEqualTo(lines.length)); - final expected = [ - for (var i = 0; i < lines.length; i++) - _matchFrame( - breakpoints[i].script, breakpoints[i].function, lines[i]) - ]; - expect(stack.frames, containsAll(expected)); - - // Verify that expression evaluation is not failing. - final instance = - await service.evaluateInFrame(isolate.id!, frameIndex, 'true'); - expect(instance, isA()); - } - - test('breakpoint succeeds with correct callstack', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'printEnclosingObject', - 'printEnclosingObject', - mainScript, - ), - BreakpointTestData( - 'printEnclosingFunctionMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint( - breakpoints[0], () => testCallStack(breakpoints)); - }); - - test('expression evaluation succeeds on parent frame', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'testLibraryClassConstructor', - 'new', - testLibraryScript, - ), - BreakpointTestData( - 'createLibraryObject', - 'printFieldFromLibraryClass', - mainScript, - ), - BreakpointTestData( - 'callPrintFieldFromLibraryClass', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[0], - () => testCallStack(breakpoints, frameIndex: 2)); - }); - - test('breakpoint inside a line gives correct callstack', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'newEnclosedClass', - 'new', - mainScript, - ), - BreakpointTestData( - 'printNestedObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint( - breakpoints[0], () => testCallStack(breakpoints)); - }); - - test('breakpoint gives correct callstack after step out', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'newEnclosedClass', - 'new', - mainScript, - ), - BreakpointTestData( - 'printEnclosingObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[0], () async { - await service.resume(isolate.id!, step: 'Out'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted); - return testCallStack([breakpoints[1], breakpoints[2]]); + group( + 'shared context |', + () { + // Enable verbose logging for debugging. + final debug = false; + + for (var nullSafety in NullSafety.values) { + group( + '${nullSafety.name} null safety |', + () { + final soundNullSafety = nullSafety == NullSafety.sound; + final setup = + soundNullSafety ? TestSetup.sound() : TestSetup.unsound(); + final context = setup.context; + + setUpAll(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + compilationMode: CompilationMode.buildDaemon, + enableExpressionEvaluation: true, + verboseCompiler: debug, + ); }); - }); - - test('breakpoint gives correct callstack after step in', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'newEnclosedClass', - 'new', - mainScript, - ), - BreakpointTestData( - 'printNestedObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[1], () async { - await service.resume(isolate.id!, step: 'Into'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted); - return testCallStack(breakpoints); + + tearDownAll(() async { + await context.tearDown(); }); - }); - - test('breakpoint gives correct callstack after step into chain calls', - () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'createObjectWithMethod', - 'createObject', - mainScript, - ), - BreakpointTestData( - // This is currently incorrect, should be printObjectMultiLine. - // See issue: https://github.com/dart-lang/sdk/issues/48874 - 'printMultiLine', - 'printObjectMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintObjectMultiLine', - '', - mainScript, - ), - ]; - final bp = BreakpointTestData( - 'printMultiLine', 'printObjectMultiLine', mainScript); - await onBreakPoint(bp, () async { - await service.resume(isolate.id!, step: 'Into'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted); - return testCallStack(breakpoints); + + group('callStack |', () { + late ChromeProxyService service; + VM vm; + late Isolate isolate; + ScriptList scripts; + late ScriptRef mainScript; + late ScriptRef testLibraryScript; + late Stream stream; + + setUp(() async { + setCurrentLogWriter(debug: debug); + service = setup.service; + vm = await service.getVM(); + isolate = await service.getIsolate(vm.isolates!.first.id!); + scripts = await service.getScripts(isolate.id!); + + await service.streamListen('Debug'); + stream = service.onEvent('Debug'); + + final testPackage = + soundNullSafety ? '_test_package_sound' : '_test_package'; + + mainScript = scripts.scripts! + .firstWhere((each) => each.uri!.contains('main.dart')); + testLibraryScript = scripts.scripts!.firstWhere((each) => each + .uri! + .contains('package:$testPackage/test_library.dart')); + }); + + tearDown(() async { + await service.resume(isolate.id!); + }); + + Future onBreakPoint(BreakpointTestData breakpoint, + Future Function() body) async { + Breakpoint? bp; + try { + final bpId = breakpoint.bpId; + final script = breakpoint.script; + final line = await context.findBreakpointLine( + bpId, isolate.id!, script); + bp = await setup.service.addBreakpointWithScriptUri( + isolate.id!, script.uri!, line); + + expect(bp, isNotNull); + expect(bp.location, _matchBpLocation(script, line, 0)); + + await stream.firstWhere((Event event) => + event.kind == EventKind.kPauseBreakpoint); + + await body(); + } finally { + // Remove breakpoint so it doesn't impact other tests or retries. + if (bp != null) { + await setup.service.removeBreakpoint(isolate.id!, bp.id!); + } + } + } + + Future testCallStack(List breakpoints, + {int frameIndex = 1}) async { + // Find lines the breakpoints are located on. + final lines = await Future.wait(breakpoints.map((frame) => + context.findBreakpointLine( + frame.bpId, isolate.id!, frame.script))); + + // Get current stack. + final stack = await service.getStack(isolate.id!); + + // Verify the stack is correct. + expect( + stack.frames!.length, greaterThanOrEqualTo(lines.length)); + final expected = [ + for (var i = 0; i < lines.length; i++) + _matchFrame(breakpoints[i].script, breakpoints[i].function, + lines[i]) + ]; + expect(stack.frames, containsAll(expected)); + + // Verify that expression evaluation is not failing. + final instance = await service.evaluateInFrame( + isolate.id!, frameIndex, 'true'); + expect(instance, isA()); + } + + test('breakpoint succeeds with correct callstack', () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'printEnclosingObject', + 'printEnclosingObject', + mainScript, + ), + BreakpointTestData( + 'printEnclosingFunctionMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint( + breakpoints[0], () => testCallStack(breakpoints)); + }); + + test('expression evaluation succeeds on parent frame', () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'testLibraryClassConstructor', + 'new', + testLibraryScript, + ), + BreakpointTestData( + 'createLibraryObject', + 'printFieldFromLibraryClass', + mainScript, + ), + BreakpointTestData( + 'callPrintFieldFromLibraryClass', + '', + mainScript, + ), + ]; + await onBreakPoint(breakpoints[0], + () => testCallStack(breakpoints, frameIndex: 2)); + }); + + test('breakpoint inside a line gives correct callstack', + () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'newEnclosedClass', + 'new', + mainScript, + ), + BreakpointTestData( + 'printNestedObjectMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint( + breakpoints[0], () => testCallStack(breakpoints)); + }); + + test('breakpoint gives correct callstack after step out', + () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'newEnclosedClass', + 'new', + mainScript, + ), + BreakpointTestData( + 'printEnclosingObjectMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint(breakpoints[0], () async { + await service.resume(isolate.id!, step: 'Out'); + await stream.firstWhere((Event event) => + event.kind == EventKind.kPauseInterrupted); + return testCallStack([breakpoints[1], breakpoints[2]]); + }); + }); + + test('breakpoint gives correct callstack after step in', + () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'newEnclosedClass', + 'new', + mainScript, + ), + BreakpointTestData( + 'printNestedObjectMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint(breakpoints[1], () async { + await service.resume(isolate.id!, step: 'Into'); + await stream.firstWhere((Event event) => + event.kind == EventKind.kPauseInterrupted); + return testCallStack(breakpoints); + }); + }); + + test( + 'breakpoint gives correct callstack after step into chain calls', + () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'createObjectWithMethod', + 'createObject', + mainScript, + ), + BreakpointTestData( + // This is currently incorrect, should be printObjectMultiLine. + // See issue: https://github.com/dart-lang/sdk/issues/48874 + 'printMultiLine', + 'printObjectMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintObjectMultiLine', + '', + mainScript, + ), + ]; + final bp = BreakpointTestData( + 'printMultiLine', 'printObjectMultiLine', mainScript); + await onBreakPoint(bp, () async { + await service.resume(isolate.id!, step: 'Into'); + await stream.firstWhere((Event event) => + event.kind == EventKind.kPauseInterrupted); + return testCallStack(breakpoints); + }); + }); }); - }); - }); - }); - } - }); + }, + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + skip: !supportedMode( + compilationMode: CompilationMode.buildDaemon, + nullSafetyMode: nullSafety, + ), + ); + } + }, + ); } Matcher _matchFrame(ScriptRef script, String function, int line) => isA() diff --git a/dwds/test/build_daemon_circular_evaluate_test.dart b/dwds/test/build_daemon_circular_evaluate_test.dart index 6ff523a75..4f866dace 100644 --- a/dwds/test/build_daemon_circular_evaluate_test.dart +++ b/dwds/test/build_daemon_circular_evaluate_test.dart @@ -9,17 +9,27 @@ import 'package:test/test.dart'; import 'fixtures/context.dart'; import 'evaluate_circular_common.dart'; +import 'utils/version_compatibility.dart'; + void main() async { // Enable verbose logging for debugging. final debug = false; for (var nullSafety in NullSafety.values) { - group('${nullSafety.name} null safety |', () { - testAll( + group( + '${nullSafety.name} null safety |', + () { + testAll( + compilationMode: CompilationMode.buildDaemon, + nullSafety: nullSafety, + debug: debug, + ); + }, + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + skip: !supportedMode( compilationMode: CompilationMode.buildDaemon, - nullSafety: nullSafety, - debug: debug, - ); - }); + nullSafetyMode: nullSafety, + ), + ); } } diff --git a/dwds/test/build_daemon_evaluate_test.dart b/dwds/test/build_daemon_evaluate_test.dart index f85b0de46..5dacc394c 100644 --- a/dwds/test/build_daemon_evaluate_test.dart +++ b/dwds/test/build_daemon_evaluate_test.dart @@ -8,18 +8,27 @@ import 'package:test/test.dart'; import 'fixtures/context.dart'; import 'evaluate_common.dart'; +import 'utils/version_compatibility.dart'; void main() async { // Enable verbose logging for debugging. final debug = false; for (var nullSafety in NullSafety.values) { - group('${nullSafety.name} null safety |', () { - testAll( + group( + '${nullSafety.name} null safety |', + () { + testAll( + compilationMode: CompilationMode.buildDaemon, + nullSafety: nullSafety, + debug: debug, + ); + }, + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + skip: !supportedMode( compilationMode: CompilationMode.buildDaemon, - nullSafety: nullSafety, - debug: debug, - ); - }); + nullSafetyMode: nullSafety, + ), + ); } } diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart index eae7a3fe5..565b42f7c 100644 --- a/dwds/test/chrome_proxy_service_test.dart +++ b/dwds/test/chrome_proxy_service_test.dart @@ -13,7 +13,6 @@ import 'package:dwds/src/services/chrome_proxy_service.dart'; import 'package:dwds/src/utilities/dart_uri.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; -import 'package:pub_semver/pub_semver.dart' as semver; import 'package:test/test.dart'; import 'package:vm_service/vm_service.dart'; import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; @@ -126,7 +125,7 @@ void main() { test('addBreakpointWithScriptUri absolute file URI', () async { final current = context.workingDirectory; - final test = path.join(path.dirname(current), '_test'); + final test = path.join(path.dirname(current), '_testSound'); final scriptPath = Uri.parse(mainScript.uri!).path.substring(1); final fullPath = path.join(test, scriptPath); final fileUri = Uri.file(fullPath); @@ -464,56 +463,46 @@ void main() { expect(library1, equals(library2)); }); - test( - 'Classes', - () async { - final testClass = await service.getObject( - isolate.id!, rootLibrary!.classes!.first.id!) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate( - (FuncRef f) => f.name == 'staticHello' && f.isStatic!), - predicate((FuncRef f) => f.name == 'message' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic!), - predicate((FuncRef f) => f.name == '_equals' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'toString' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'runtimeType' && !f.isStatic!), - ])); - expect( - testClass.fields, - unorderedEquals([ - predicate((FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - f.isFinal!), - predicate((FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - !f.isFinal!), - predicate((FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic! && - !f.isConst! && - !f.isFinal!), - ])); - }, - // TODO(elliette): Remove once 2.15.0 is the stable release. - skip: semver.Version.parse(Platform.version.split(' ').first) >= - semver.Version.parse('2.15.0-268.18.beta') - ? null - : 'SDK does not expose static member information.', - ); + test('Classes', () async { + final testClass = await service.getObject( + isolate.id!, rootLibrary!.classes!.first.id!) as Class; + expect( + testClass.functions, + unorderedEquals([ + predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic!), + predicate((FuncRef f) => f.name == 'message' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'hello' && !f.isStatic!), + predicate((FuncRef f) => f.name == '_equals' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'toString' && !f.isStatic!), + predicate( + (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'runtimeType' && !f.isStatic!), + ])); + expect( + testClass.fields, + unorderedEquals([ + predicate((FieldRef f) => + f.name == 'message' && + f.declaredType != null && + !f.isStatic! && + !f.isConst! && + f.isFinal!), + predicate((FieldRef f) => + f.name == 'notFinal' && + f.declaredType != null && + !f.isStatic! && + !f.isConst! && + !f.isFinal!), + predicate((FieldRef f) => + f.name == 'staticMessage' && + f.declaredType != null && + f.isStatic! && + !f.isConst! && + !f.isFinal!), + ])); + }, skip: 'https://github.com/dart-lang/webdev/issues/1818'); test('Runtime classes', () async { final testClass = await service.getObject( @@ -612,15 +601,6 @@ void main() { expect(obj.valueAsString, '42'); }); - test('null', () async { - final ref = await service.evaluate( - isolate.id!, bootstrap!.id!, 'helloNum(null)') as InstanceRef; - final obj = await service.getObject(isolate.id!, ref.id!) as Instance; - expect(obj.kind, InstanceKind.kNull); - expect(obj.classRef!.name, 'Null'); - expect(obj.valueAsString, 'null'); - }); - test('Scripts', () async { final scripts = await service.getScripts(isolate.id!); assert(scripts.scripts!.isNotEmpty); @@ -740,63 +720,52 @@ void main() { expect(world.offset, 3); }); - test( - 'offset/count parameters are ignored for Classes', - () async { - final testClass = await service.getObject( - isolate.id!, - rootLibrary!.classes!.first.id!, - offset: 100, - count: 100, - ) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate( - (FuncRef f) => f.name == 'staticHello' && f.isStatic!), - predicate((FuncRef f) => f.name == 'message' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'notFinal' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic!), - predicate((FuncRef f) => f.name == '_equals' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'hashCode' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'toString' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'runtimeType' && !f.isStatic!), - ])); - expect( - testClass.fields, - unorderedEquals([ - predicate((FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - f.isFinal!), - predicate((FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - !f.isFinal!), - predicate((FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic! && - !f.isConst! && - !f.isFinal!), - ])); - }, - // TODO(elliette): Remove once 2.15.0 is the stable release. - skip: semver.Version.parse(Platform.version.split(' ').first) >= - semver.Version.parse('2.15.0-268.18.beta') - ? null - : 'SDK does not expose static member information.', - ); + test('offset/count parameters are ignored for Classes', () async { + final testClass = await service.getObject( + isolate.id!, + rootLibrary!.classes!.first.id!, + offset: 100, + count: 100, + ) as Class; + expect( + testClass.functions, + unorderedEquals([ + predicate( + (FuncRef f) => f.name == 'staticHello' && f.isStatic!), + predicate((FuncRef f) => f.name == 'message' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'hello' && !f.isStatic!), + predicate((FuncRef f) => f.name == '_equals' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic!), + predicate((FuncRef f) => f.name == 'toString' && !f.isStatic!), + predicate( + (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic!), + predicate( + (FuncRef f) => f.name == 'runtimeType' && !f.isStatic!), + ])); + expect( + testClass.fields, + unorderedEquals([ + predicate((FieldRef f) => + f.name == 'message' && + f.declaredType != null && + !f.isStatic! && + !f.isConst! && + f.isFinal!), + predicate((FieldRef f) => + f.name == 'notFinal' && + f.declaredType != null && + !f.isStatic! && + !f.isConst! && + !f.isFinal!), + predicate((FieldRef f) => + f.name == 'staticMessage' && + f.declaredType != null && + f.isStatic! && + !f.isConst! && + !f.isFinal!), + ])); + }, skip: 'https://github.com/dart-lang/webdev/issues/1818'); test('offset/count parameters are ignored for bools', () async { final ref = await service.evaluate( @@ -838,7 +807,7 @@ void main() { expect(obj.kind, InstanceKind.kNull); expect(obj.classRef!.name, 'Null'); expect(obj.valueAsString, 'null'); - }); + }, skip: 'https://github.com/dart-lang/webdev/issues/1818'); }); }); @@ -860,8 +829,8 @@ void main() { // Containts part files as well. expect(scriptUris, contains(endsWith('part.dart'))); - expect(scriptUris, - contains('package:intl/src/intl/date_format_helpers.dart')); + expect( + scriptUris, contains('package:intl/src/date_format_internal.dart')); }); group('getSourceReport', () { @@ -1145,7 +1114,8 @@ void main() { .firstWhere((event) => event.kind == EventKind.kPauseException); expect(event.exception, isNotNull); // Check that the exception stack trace has been mapped to Dart source files. - expect(event.exception!.valueAsString, contains('main.dart')); + // TODO(https://github.com/dart-lang/webdev/issues/1821) Uncomment. + // expect(event.exception!.valueAsString, contains('main.dart')); final stack = await service.getStack(isolateId!); expect(stack, isNotNull); @@ -1368,7 +1338,7 @@ void main() { expect( resolvedUris.uris, containsAll([ - contains('/_test/example/hello_world/main.dart'), + contains('/_testSound/example/hello_world/main.dart'), contains('/lib/path.dart'), contains('/lib/src/path_set.dart'), ])); diff --git a/dwds/test/dart_uri_file_uri_test.dart b/dwds/test/dart_uri_file_uri_test.dart index 80825dacc..3ac02a9d6 100644 --- a/dwds/test/dart_uri_file_uri_test.dart +++ b/dwds/test/dart_uri_file_uri_test.dart @@ -10,12 +10,15 @@ import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'fixtures/context.dart'; +import 'utils/version_compatibility.dart'; final context = TestContext( - directory: p.join('..', 'fixtures', '_testPackage'), - entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); + directory: p.join('..', 'fixtures', '_testPackage'), + entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web', + nullSafety: NullSafety.weak, +); final dwdsDir = Directory.current.absolute.path; @@ -30,60 +33,68 @@ final testPackageDir = context.workingDirectory; // // These tests are separated out because we need a running isolate in order to // look up packages. +// TODO(https://github.com/dart-lang/webdev/issues/1818): Switch test over for +// testing sound null-safety. void main() { for (final compilationMode in CompilationMode.values) { - group('$compilationMode |', () { - for (final useDebuggerModuleNames in [false, true]) { - group('Debugger module names: $useDebuggerModuleNames |', () { - final appServerPath = - compilationMode == CompilationMode.frontendServer - ? 'web/main.dart' - : 'main.dart'; + group( + '$compilationMode |', + () { + for (final useDebuggerModuleNames in [false, true]) { + group('Debugger module names: $useDebuggerModuleNames |', () { + final appServerPath = + compilationMode == CompilationMode.frontendServer + ? 'web/main.dart' + : 'main.dart'; - final serverPath = - compilationMode == CompilationMode.frontendServer && - useDebuggerModuleNames - ? 'packages/_testPackage/lib/test_library.dart' - : 'packages/_test_package/test_library.dart'; + final serverPath = + compilationMode == CompilationMode.frontendServer && + useDebuggerModuleNames + ? 'packages/_testPackage/lib/test_library.dart' + : 'packages/_test_package/test_library.dart'; - final anotherServerPath = - compilationMode == CompilationMode.frontendServer && - useDebuggerModuleNames - ? 'packages/_test/lib/library.dart' - : 'packages/_test/library.dart'; + final anotherServerPath = + compilationMode == CompilationMode.frontendServer && + useDebuggerModuleNames + ? 'packages/_test/lib/library.dart' + : 'packages/_test/library.dart'; - setUpAll(() async { - await context.setUp( - compilationMode: compilationMode, - useDebuggerModuleNames: useDebuggerModuleNames, - ); - }); + setUpAll(() async { + await context.setUp( + compilationMode: compilationMode, + useDebuggerModuleNames: useDebuggerModuleNames, + ); + }); - tearDownAll(() async { - await context.tearDown(); - }); + tearDownAll(() async { + await context.tearDown(); + }); - test('file path to org-dartlang-app', () { - final webMain = - Uri.file(p.join(testPackageDir, 'web', 'main.dart')); - final uri = DartUri('$webMain'); - expect(uri.serverPath, appServerPath); - }); + test('file path to org-dartlang-app', () { + final webMain = + Uri.file(p.join(testPackageDir, 'web', 'main.dart')); + final uri = DartUri('$webMain'); + expect(uri.serverPath, appServerPath); + }); - test('file path to this package', () { - final testPackageLib = - Uri.file(p.join(testPackageDir, 'lib', 'test_library.dart')); - final uri = DartUri('$testPackageLib'); - expect(uri.serverPath, serverPath); - }); + test('file path to this package', () { + final testPackageLib = + Uri.file(p.join(testPackageDir, 'lib', 'test_library.dart')); + final uri = DartUri('$testPackageLib'); + expect(uri.serverPath, serverPath); + }); - test('file path to another package', () { - final testLib = Uri.file(p.join(testDir, 'lib', 'library.dart')); - final dartUri = DartUri('$testLib'); - expect(dartUri.serverPath, anotherServerPath); + test('file path to another package', () { + final testLib = Uri.file(p.join(testDir, 'lib', 'library.dart')); + final dartUri = DartUri('$testLib'); + expect(dartUri.serverPath, anotherServerPath); + }); }); - }); - } - }); + } + }, + // TODO(https://github.com/dart-lang/webdev/issues/1818): Re-enable. + skip: !supportedMode( + compilationMode: compilationMode, nullSafetyMode: NullSafety.weak), + ); } } diff --git a/dwds/test/debug_extension_test.dart b/dwds/test/debug_extension_test.dart index 7f09e9f87..25ebdfb05 100644 --- a/dwds/test/debug_extension_test.dart +++ b/dwds/test/debug_extension_test.dart @@ -99,9 +99,9 @@ void main() async { scripts.values.map((s) => s.url), containsAllInOrder([ contains('stack_trace_mapper.dart.js'), - contains('hello_world/main.unsound.ddc.js'), - contains('packages/path/path.unsound.ddc.js'), - contains('dev_compiler/dart_sdk.js'), + contains('hello_world/main.sound.ddc.js'), + contains('packages/path/path.sound.ddc.js'), + contains('dev_compiler/dart_sdk.sound.js'), contains('dwds/src/injected/client.js'), ])); }); @@ -191,9 +191,9 @@ void main() async { scripts.values.map((s) => s.url), containsAllInOrder([ contains('stack_trace_mapper.dart.js'), - contains('hello_world/main.unsound.ddc.js'), - contains('packages/path/path.unsound.ddc.js'), - contains('dev_compiler/dart_sdk.js'), + contains('hello_world/main.sound.ddc.js'), + contains('packages/path/path.sound.ddc.js'), + contains('dev_compiler/dart_sdk.sound.js'), contains('dwds/src/injected/client.js'), ])); }); diff --git a/dwds/test/evaluate_circular_common.dart b/dwds/test/evaluate_circular_common.dart index 0de304df4..f633badc5 100644 --- a/dwds/test/evaluate_circular_common.dart +++ b/dwds/test/evaluate_circular_common.dart @@ -16,18 +16,21 @@ import 'fixtures/context.dart'; import 'fixtures/logging.dart'; class TestSetup { - static TestContext createContext(String index, String packageRoot) => + static TestContext createContext( + String index, String packageRoot, NullSafety nullSafety) => TestContext( - directory: p.join('..', 'fixtures', packageRoot), - entry: p.join('..', 'fixtures', packageRoot, 'web', 'main.dart'), - path: index, - pathToServe: 'web'); + directory: p.join('..', 'fixtures', packageRoot), + entry: p.join('..', 'fixtures', packageRoot, 'web', 'main.dart'), + path: index, + pathToServe: 'web', + nullSafety: nullSafety, + ); static TestContext contextUnsound(String index) => - createContext(index, '_testCircular2'); + createContext(index, '_testCircular2', NullSafety.weak); static TestContext contextSound(String index) => - createContext(index, '_testCircular2Sound'); + createContext(index, '_testCircular2Sound', NullSafety.sound); TestContext context; @@ -87,7 +90,6 @@ void testAll({ setCurrentLogWriter(debug: debug); await context.setUp( compilationMode: compilationMode, - nullSafety: nullSafety, enableExpressionEvaluation: true, useDebuggerModuleNames: useDebuggerModuleNames, verboseCompiler: debug, diff --git a/dwds/test/evaluate_common.dart b/dwds/test/evaluate_common.dart index 908158e18..e0829d4ae 100644 --- a/dwds/test/evaluate_common.dart +++ b/dwds/test/evaluate_common.dart @@ -16,18 +16,20 @@ import 'fixtures/context.dart'; import 'fixtures/logging.dart'; class TestSetup { - static TestContext createContext(String index, String packageRoot) => + static TestContext createContext( + String index, String packageRoot, NullSafety nullSafety) => TestContext( directory: p.join('..', 'fixtures', packageRoot), entry: p.join('..', 'fixtures', packageRoot, 'web', 'main.dart'), path: index, - pathToServe: 'web'); + pathToServe: 'web', + nullSafety: nullSafety); static TestContext contextUnsound(String index) => - createContext(index, '_testPackage'); + createContext(index, '_testPackage', NullSafety.weak); static TestContext contextSound(String index) => - createContext(index, '_testPackageSound'); + createContext(index, '_testPackageSound', NullSafety.sound); TestContext context; @@ -87,7 +89,6 @@ void testAll({ setCurrentLogWriter(debug: debug); await context.setUp( compilationMode: compilationMode, - nullSafety: nullSafety, enableExpressionEvaluation: true, useDebuggerModuleNames: useDebuggerModuleNames, verboseCompiler: debug, @@ -633,7 +634,6 @@ void testAll({ setCurrentLogWriter(debug: debug); await context.setUp( compilationMode: compilationMode, - nullSafety: nullSafety, enableExpressionEvaluation: false, verboseCompiler: debug, ); diff --git a/dwds/test/events_test.dart b/dwds/test/events_test.dart index 3ed3e7327..7d3c05101 100644 --- a/dwds/test/events_test.dart +++ b/dwds/test/events_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. // @dart = 2.9 - +@Skip('Migrate to null-safety: https://github.com/dart-lang/webdev/issues/1818') import 'dart:async'; import 'dart:io'; diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index 2fbaef572..07144df7e 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -112,15 +112,20 @@ class TestContext { /// The path part of the application URL. String path; - TestContext( - {String? directory, - String? entry, - this.path = 'hello_world/index.html', - this.pathToServe = 'example'}) { - final relativeDirectory = p.join('..', 'fixtures', '_test'); + NullSafety nullSafety; + + TestContext({ + String? directory, + String? entry, + this.nullSafety = NullSafety.sound, + this.path = 'hello_world/index.html', + this.pathToServe = 'example', + }) { + final packageName = nullSafety == NullSafety.sound ? '_testSound' : '_test'; + final relativeDirectory = p.join('..', 'fixtures', packageName); final relativeEntry = p.join( - '..', 'fixtures', '_test', 'example', 'append_body', 'main.dart'); + '..', 'fixtures', packageName, 'example', 'append_body', 'main.dart'); workingDirectory = p.normalize(p .absolute(directory ?? p.relative(relativeDirectory, from: p.current))); @@ -156,7 +161,6 @@ class TestContext { bool waitToDebug = false, UrlEncoder? urlEncoder, CompilationMode compilationMode = CompilationMode.buildDaemon, - NullSafety nullSafety = NullSafety.weak, bool enableExpressionEvaluation = false, bool verboseCompiler = false, SdkConfigurationProvider? sdkConfigurationProvider, @@ -165,6 +169,14 @@ class TestContext { bool isFlutterApp = false, bool isInternalBuild = false, }) async { + // TODO(https://github.com/dart-lang/webdev/issues/1591): Support compiling + // with sound null-safety in Frontend Server. + if (compilationMode == CompilationMode.frontendServer && + nullSafety == NullSafety.sound) { + throw Exception( + 'Frontend Server compilation does not support sound null-safety. See https://github.com/dart-lang/webdev/issues/1591'); + } + sdkConfigurationProvider ??= DefaultSdkConfigurationProvider(); try { diff --git a/dwds/test/frontend_server_breakpoint_test.dart b/dwds/test/frontend_server_breakpoint_test.dart index 1e9bd996b..7324f19ae 100644 --- a/dwds/test/frontend_server_breakpoint_test.dart +++ b/dwds/test/frontend_server_breakpoint_test.dart @@ -14,12 +14,15 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import 'fixtures/context.dart'; import 'fixtures/logging.dart'; +import 'utils/version_compatibility.dart'; final context = TestContext( - directory: p.join('..', 'fixtures', '_testPackage'), - entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); + directory: p.join('..', 'fixtures', '_testPackage'), + entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web', + nullSafety: NullSafety.weak, +); ChromeProxyService get service => fetchChromeProxyService(context.debugConnection); @@ -35,100 +38,107 @@ void main() { // currently redirected to a logger. As a result, it will be printed // regardless of the logger settings. final verboseCompiler = false; - - group('shared context', () { - setUpAll(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - compilationMode: CompilationMode.frontendServer, - verboseCompiler: verboseCompiler, - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - group('breakpoint', () { - VM vm; - late Isolate isolate; - late String isolateId; - ScriptList scripts; - late ScriptRef mainScript; - late String mainScriptUri; - late Stream stream; - - setUp(() async { + group( + 'shared context', + () { + setUpAll(() async { setCurrentLogWriter(debug: debug); - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts! - .firstWhere((each) => each.uri!.contains('main.dart')); - mainScriptUri = mainScript.uri!; + await context.setUp( + compilationMode: CompilationMode.frontendServer, + verboseCompiler: verboseCompiler, + ); }); - tearDown(() async { - await service.resume(isolateId); - }); - - test('set breakpoint', () async { - final line = await context.findBreakpointLine( - 'printLocal', isolateId, mainScript); - final bp = await service.addBreakpointWithScriptUri( - isolateId, mainScriptUri, line); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - expect(bp, isNotNull); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp.id!); - }); - - test('set breakpoint again', () async { - final line = await context.findBreakpointLine( - 'printLocal', isolateId, mainScript); - final bp = await service.addBreakpointWithScriptUri( - isolateId, mainScriptUri, line); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - expect(bp, isNotNull); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp.id!); + tearDownAll(() async { + await context.tearDown(); }); - test('set breakpoint inside a JavaScript line succeeds', () async { - final line = await context.findBreakpointLine( - 'printNestedObjectMultiLine', isolateId, mainScript); - final column = 0; - final bp = await service.addBreakpointWithScriptUri( - isolateId, mainScriptUri, line, - column: column); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - expect(bp, isNotNull); - expect( - bp.location, - isA() - .having((loc) => loc.script, 'script', equals(mainScript)) - .having((loc) => loc.line, 'line', equals(line)) - .having((loc) => loc.column, 'column', greaterThan(column))); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp.id!); + group('breakpoint', () { + VM vm; + late Isolate isolate; + late String isolateId; + ScriptList scripts; + late ScriptRef mainScript; + late String mainScriptUri; + late Stream stream; + + setUp(() async { + setCurrentLogWriter(debug: debug); + vm = await service.getVM(); + isolate = await service.getIsolate(vm.isolates!.first.id!); + isolateId = isolate.id!; + scripts = await service.getScripts(isolateId); + + await service.streamListen('Debug'); + stream = service.onEvent('Debug'); + + mainScript = scripts.scripts! + .firstWhere((each) => each.uri!.contains('main.dart')); + mainScriptUri = mainScript.uri!; + }); + + tearDown(() async { + await service.resume(isolateId); + }); + + test('set breakpoint', () async { + final line = await context.findBreakpointLine( + 'printLocal', isolateId, mainScript); + final bp = await service.addBreakpointWithScriptUri( + isolateId, mainScriptUri, line); + + await stream.firstWhere( + (Event event) => event.kind == EventKind.kPauseBreakpoint); + + expect(bp, isNotNull); + + // Remove breakpoint so it doesn't impact other tests. + await service.removeBreakpoint(isolateId, bp.id!); + }); + + test('set breakpoint again', () async { + final line = await context.findBreakpointLine( + 'printLocal', isolateId, mainScript); + final bp = await service.addBreakpointWithScriptUri( + isolateId, mainScriptUri, line); + + await stream.firstWhere( + (Event event) => event.kind == EventKind.kPauseBreakpoint); + + expect(bp, isNotNull); + + // Remove breakpoint so it doesn't impact other tests. + await service.removeBreakpoint(isolateId, bp.id!); + }); + + test('set breakpoint inside a JavaScript line succeeds', () async { + final line = await context.findBreakpointLine( + 'printNestedObjectMultiLine', isolateId, mainScript); + final column = 0; + final bp = await service.addBreakpointWithScriptUri( + isolateId, mainScriptUri, line, + column: column); + + await stream.firstWhere( + (Event event) => event.kind == EventKind.kPauseBreakpoint); + + expect(bp, isNotNull); + expect( + bp.location, + isA() + .having((loc) => loc.script, 'script', equals(mainScript)) + .having((loc) => loc.line, 'line', equals(line)) + .having((loc) => loc.column, 'column', greaterThan(column))); + + // Remove breakpoint so it doesn't impact other tests. + await service.removeBreakpoint(isolateId, bp.id!); + }); }); - }); - }); + }, + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + skip: !supportedMode( + compilationMode: CompilationMode.frontendServer, + nullSafetyMode: NullSafety.weak, + ), + ); } diff --git a/dwds/test/frontend_server_callstack_test.dart b/dwds/test/frontend_server_callstack_test.dart index e3b0e1b62..70479df5e 100644 --- a/dwds/test/frontend_server_callstack_test.dart +++ b/dwds/test/frontend_server_callstack_test.dart @@ -14,19 +14,24 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import 'fixtures/context.dart'; import 'fixtures/logging.dart'; +import 'utils/version_compatibility.dart'; class TestSetup { static final contextUnsound = TestContext( - directory: p.join('..', 'fixtures', '_testPackage'), - entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); + directory: p.join('..', 'fixtures', '_testPackage'), + entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web', + nullSafety: NullSafety.weak, + ); static final contextSound = TestContext( - directory: p.join('..', 'fixtures', '_testPackageSound'), - entry: p.join('..', 'fixtures', '_testPackageSound', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); + directory: p.join('..', 'fixtures', '_testPackageSound'), + entry: p.join('..', 'fixtures', '_testPackageSound', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web', + nullSafety: NullSafety.sound, + ); TestContext context; @@ -45,265 +50,273 @@ void main() { final debug = false; for (var nullSafety in NullSafety.values) { - final soundNullSafety = nullSafety == NullSafety.sound; - final setup = soundNullSafety ? TestSetup.sound() : TestSetup.unsound(); - final context = setup.context; - - group('${nullSafety.name} null safety |', () { - setUpAll(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - compilationMode: CompilationMode.frontendServer, - nullSafety: nullSafety, - enableExpressionEvaluation: true, - verboseCompiler: debug); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - group('callStack |', () { - late ChromeProxyService service; - VM vm; - late Isolate isolate; - late String isolateId; - ScriptList scripts; - late ScriptRef mainScript; - late ScriptRef testLibraryScript; - late Stream stream; - - setUp(() async { + group( + '${nullSafety.name} null safety |', + () { + final soundNullSafety = nullSafety == NullSafety.sound; + final setup = + soundNullSafety ? TestSetup.sound() : TestSetup.unsound(); + final context = setup.context; + + setUpAll(() async { setCurrentLogWriter(debug: debug); - service = setup.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - final testPackage = - soundNullSafety ? '_test_package_sound' : '_test_package'; - - mainScript = scripts.scripts! - .firstWhere((each) => each.uri!.contains('main.dart')); - testLibraryScript = scripts.scripts!.firstWhere((each) => - each.uri!.contains('package:$testPackage/test_library.dart')); + await context.setUp( + compilationMode: CompilationMode.frontendServer, + enableExpressionEvaluation: true, + verboseCompiler: debug); }); - tearDown(() async { - await service.resume(isolateId); + tearDownAll(() async { + await context.tearDown(); }); - Future onBreakPoint(BreakpointTestData breakpoint, - Future Function() body) async { - Breakpoint? bp; - try { - final bpId = breakpoint.bpId; - final script = breakpoint.script; - final line = - await context.findBreakpointLine(bpId, isolateId, script); - bp = await setup.service - .addBreakpointWithScriptUri(isolateId, script.uri!, line); - - expect(bp, isNotNull); - expect(bp.location, _matchBpLocation(script, line, 0)); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - await body(); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await setup.service.removeBreakpoint(isolateId, bp.id!); + group('callStack |', () { + late ChromeProxyService service; + VM vm; + late Isolate isolate; + late String isolateId; + ScriptList scripts; + late ScriptRef mainScript; + late ScriptRef testLibraryScript; + late Stream stream; + + setUp(() async { + setCurrentLogWriter(debug: debug); + service = setup.service; + vm = await service.getVM(); + isolate = await service.getIsolate(vm.isolates!.first.id!); + isolateId = isolate.id!; + scripts = await service.getScripts(isolateId); + + await service.streamListen('Debug'); + stream = service.onEvent('Debug'); + + final testPackage = + soundNullSafety ? '_test_package_sound' : '_test_package'; + + mainScript = scripts.scripts! + .firstWhere((each) => each.uri!.contains('main.dart')); + testLibraryScript = scripts.scripts!.firstWhere((each) => + each.uri!.contains('package:$testPackage/test_library.dart')); + }); + + tearDown(() async { + await service.resume(isolateId); + }); + + Future onBreakPoint(BreakpointTestData breakpoint, + Future Function() body) async { + Breakpoint? bp; + try { + final bpId = breakpoint.bpId; + final script = breakpoint.script; + final line = + await context.findBreakpointLine(bpId, isolateId, script); + bp = await setup.service + .addBreakpointWithScriptUri(isolateId, script.uri!, line); + + expect(bp, isNotNull); + expect(bp.location, _matchBpLocation(script, line, 0)); + + await stream.firstWhere( + (Event event) => event.kind == EventKind.kPauseBreakpoint); + + await body(); + } finally { + // Remove breakpoint so it doesn't impact other tests or retries. + if (bp != null) { + await setup.service.removeBreakpoint(isolateId, bp.id!); + } } } - } - - Future testCallStack(List breakpoints, - {int frameIndex = 1}) async { - // Find lines the breakpoints are located on. - final lines = await Future.wait(breakpoints.map((frame) => context - .findBreakpointLine(frame.bpId, isolateId, frame.script))); - - // Get current stack. - final stack = await service.getStack(isolateId); - - // Verify the stack is correct. - expect(stack.frames!.length, greaterThanOrEqualTo(lines.length)); - final expected = [ - for (var i = 0; i < lines.length; i++) - _matchFrame( - breakpoints[i].script, breakpoints[i].function, lines[i]) - ]; - expect(stack.frames, containsAll(expected)); - - // Verify that expression evaluation is not failing. - final instance = - await service.evaluateInFrame(isolateId, frameIndex, 'true'); - expect(instance, isA()); - } - - test('breakpoint succeeds with correct callstack', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'printEnclosingObject', - 'printEnclosingObject', - mainScript, - ), - BreakpointTestData( - 'printEnclosingFunctionMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint( - breakpoints[0], () => testCallStack(breakpoints)); - }); - test('expression evaluation succeeds on parent frame', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'testLibraryClassConstructor', - 'new', - testLibraryScript, - ), - BreakpointTestData( - 'createLibraryObject', - 'printFieldFromLibraryClass', - mainScript, - ), - BreakpointTestData( - 'callPrintFieldFromLibraryClass', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[0], - () => testCallStack(breakpoints, frameIndex: 2)); - }); + Future testCallStack(List breakpoints, + {int frameIndex = 1}) async { + // Find lines the breakpoints are located on. + final lines = await Future.wait(breakpoints.map((frame) => context + .findBreakpointLine(frame.bpId, isolateId, frame.script))); + + // Get current stack. + final stack = await service.getStack(isolateId); + + // Verify the stack is correct. + expect(stack.frames!.length, greaterThanOrEqualTo(lines.length)); + final expected = [ + for (var i = 0; i < lines.length; i++) + _matchFrame( + breakpoints[i].script, breakpoints[i].function, lines[i]) + ]; + expect(stack.frames, containsAll(expected)); + + // Verify that expression evaluation is not failing. + final instance = + await service.evaluateInFrame(isolateId, frameIndex, 'true'); + expect(instance, isA()); + } - test('breakpoint inside a line gives correct callstack', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'newEnclosedClass', - 'new', - mainScript, - ), - BreakpointTestData( - 'printNestedObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint( - breakpoints[0], () => testCallStack(breakpoints)); - }); + test('breakpoint succeeds with correct callstack', () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'printEnclosingObject', + 'printEnclosingObject', + mainScript, + ), + BreakpointTestData( + 'printEnclosingFunctionMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint( + breakpoints[0], () => testCallStack(breakpoints)); + }); - test('breakpoint gives correct callstack after step out', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'newEnclosedClass', - 'new', - mainScript, - ), - BreakpointTestData( - 'printEnclosingObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[0], () async { - await service.resume(isolateId, step: 'Out'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted); - return testCallStack([breakpoints[1], breakpoints[2]]); + test('expression evaluation succeeds on parent frame', () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'testLibraryClassConstructor', + 'new', + testLibraryScript, + ), + BreakpointTestData( + 'createLibraryObject', + 'printFieldFromLibraryClass', + mainScript, + ), + BreakpointTestData( + 'callPrintFieldFromLibraryClass', + '', + mainScript, + ), + ]; + await onBreakPoint(breakpoints[0], + () => testCallStack(breakpoints, frameIndex: 2)); }); - }); - test('breakpoint gives correct callstack after step in', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'newEnclosedClass', - 'new', - mainScript, - ), - BreakpointTestData( - 'printNestedObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[1], () async { - await service.resume(isolateId, step: 'Into'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted); - return testCallStack(breakpoints); + test('breakpoint inside a line gives correct callstack', () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'newEnclosedClass', + 'new', + mainScript, + ), + BreakpointTestData( + 'printNestedObjectMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint( + breakpoints[0], () => testCallStack(breakpoints)); + }); + + test('breakpoint gives correct callstack after step out', () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'newEnclosedClass', + 'new', + mainScript, + ), + BreakpointTestData( + 'printEnclosingObjectMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint(breakpoints[0], () async { + await service.resume(isolateId, step: 'Out'); + await stream.firstWhere( + (Event event) => event.kind == EventKind.kPauseInterrupted); + return testCallStack([breakpoints[1], breakpoints[2]]); + }); + }); + + test('breakpoint gives correct callstack after step in', () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'newEnclosedClass', + 'new', + mainScript, + ), + BreakpointTestData( + 'printNestedObjectMultiLine', + 'printNestedObjectsMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintEnclosingFunctionMultiLine', + '', + mainScript, + ), + ]; + await onBreakPoint(breakpoints[1], () async { + await service.resume(isolateId, step: 'Into'); + await stream.firstWhere( + (Event event) => event.kind == EventKind.kPauseInterrupted); + return testCallStack(breakpoints); + }); }); - }); - test('breakpoint gives correct callstack after step into chain calls', - () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'createObjectWithMethod', - 'createObject', - mainScript, - ), - BreakpointTestData( - // This is currently incorrect, should be printObjectMultiLine. - // See issue: https://github.com/dart-lang/sdk/issues/48874 - 'printMultiLine', - 'printObjectMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintObjectMultiLine', - '', - mainScript, - ), - ]; - final bp = BreakpointTestData( - 'printMultiLine', 'printObjectMultiLine', mainScript); - await onBreakPoint(bp, () async { - await service.resume(isolateId, step: 'Into'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted); - return testCallStack(breakpoints); + test( + 'breakpoint gives correct callstack after step into chain calls', + () async { + // Expected breakpoints on the stack + final breakpoints = [ + BreakpointTestData( + 'createObjectWithMethod', + 'createObject', + mainScript, + ), + BreakpointTestData( + // This is currently incorrect, should be printObjectMultiLine. + // See issue: https://github.com/dart-lang/sdk/issues/48874 + 'printMultiLine', + 'printObjectMultiLine', + mainScript, + ), + BreakpointTestData( + 'callPrintObjectMultiLine', + '', + mainScript, + ), + ]; + final bp = BreakpointTestData( + 'printMultiLine', 'printObjectMultiLine', mainScript); + await onBreakPoint(bp, () async { + await service.resume(isolateId, step: 'Into'); + await stream.firstWhere( + (Event event) => event.kind == EventKind.kPauseInterrupted); + return testCallStack(breakpoints); + }); }); }); - }); - }, // https://github.com/dart-lang/webdev/issues/1591 - skip: soundNullSafety); + }, + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + skip: !supportedMode( + compilationMode: CompilationMode.frontendServer, + nullSafetyMode: nullSafety, + ), + ); } }); } diff --git a/dwds/test/frontend_server_circular_evaluate_test.dart b/dwds/test/frontend_server_circular_evaluate_test.dart index 448f83280..3bba98e68 100644 --- a/dwds/test/frontend_server_circular_evaluate_test.dart +++ b/dwds/test/frontend_server_circular_evaluate_test.dart @@ -11,6 +11,7 @@ import 'package:test/test.dart'; import 'fixtures/context.dart'; import 'evaluate_circular_common.dart'; +import 'utils/version_compatibility.dart'; void main() async { // Enable verbose logging for debugging. @@ -25,25 +26,27 @@ void main() async { for (var nullSafety in NullSafety.values) { group('${nullSafety.name} null safety |', () { for (var indexBaseMode in IndexBaseMode.values) { - group( - 'with ${indexBaseMode.name} |', - () { - testAll( - compilationMode: CompilationMode.frontendServer, - indexBaseMode: indexBaseMode, - nullSafety: nullSafety, - useDebuggerModuleNames: true, - debug: debug, - ); - }, - skip: - // https://github.com/dart-lang/sdk/issues/49277 - indexBaseMode == IndexBaseMode.base && Platform.isWindows || - // https://github.com/dart-lang/webdev/issues/1591); - nullSafety == NullSafety.sound || - // Needs debugger module names change in the SDK to work. - !debuggerModuleNamesSupported, - ); + group('with ${indexBaseMode.name} |', () { + testAll( + compilationMode: CompilationMode.frontendServer, + indexBaseMode: indexBaseMode, + nullSafety: nullSafety, + useDebuggerModuleNames: true, + debug: debug, + ); + }, + skip: + // https://github.com/dart-lang/sdk/issues/49277 + indexBaseMode == IndexBaseMode.base && Platform.isWindows || + // https://github.com/dart-lang/webdev/issues/1591); + nullSafety == NullSafety.sound || + // Needs debugger module names change in the SDK to work. + !debuggerModuleNamesSupported || + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + !supportedMode( + compilationMode: CompilationMode.frontendServer, + nullSafetyMode: nullSafety, + )); } }); } diff --git a/dwds/test/frontend_server_evaluate_test.dart b/dwds/test/frontend_server_evaluate_test.dart index 56441ddb9..98503c12a 100644 --- a/dwds/test/frontend_server_evaluate_test.dart +++ b/dwds/test/frontend_server_evaluate_test.dart @@ -11,6 +11,7 @@ import 'package:test/test.dart'; import 'fixtures/context.dart'; import 'evaluate_common.dart'; +import 'utils/version_compatibility.dart'; void main() async { // Enable verbose logging for debugging. @@ -43,7 +44,13 @@ void main() async { // https://github.com/dart-lang/webdev/issues/1591 (nullSafety == NullSafety.sound) || // Needs debugger module names feature in SDK. - (useDebuggerModuleNames && !debuggerModuleNamesSupported), + (useDebuggerModuleNames && + !debuggerModuleNamesSupported) || + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + !supportedMode( + compilationMode: CompilationMode.frontendServer, + nullSafetyMode: nullSafety, + ), ); } }); diff --git a/dwds/test/package_uri_mapper_test.dart b/dwds/test/package_uri_mapper_test.dart index e6e6d3e3e..364b79ac4 100644 --- a/dwds/test/package_uri_mapper_test.dart +++ b/dwds/test/package_uri_mapper_test.dart @@ -17,19 +17,19 @@ void main() { final fileSystem = LocalFileSystem(); final packageUri = - Uri(scheme: 'package', path: '_test_package/test_library.dart'); + Uri(scheme: 'package', path: '_test_package_sound/test_library.dart'); final serverPath = useDebuggerModuleNames - ? 'packages/_testPackage/lib/test_library.dart' - : '/packages/_test_package/test_library.dart'; + ? 'packages/_testPackageSound/lib/test_library.dart' + : '/packages/_test_package_sound/test_library.dart'; final resolvedPath = - '/webdev/fixtures/_testPackage/lib/test_library.dart'; + '/webdev/fixtures/_testPackageSound/lib/test_library.dart'; final packageConfigFile = Uri.file(p.normalize(p.absolute(p.join( '..', 'fixtures', - '_testPackage', + '_testPackageSound', '.dart_tool', 'package_config.json', )))); diff --git a/dwds/test/readers/frontend_server_asset_reader_test.dart b/dwds/test/readers/frontend_server_asset_reader_test.dart index 4ee4be2eb..e5799b2bd 100644 --- a/dwds/test/readers/frontend_server_asset_reader_test.dart +++ b/dwds/test/readers/frontend_server_asset_reader_test.dart @@ -9,7 +9,9 @@ import 'package:dwds/src/readers/frontend_server_asset_reader.dart'; import 'package:path/path.dart' as p; import 'package:test/test.dart'; +import '../fixtures/context.dart'; import '../fixtures/utilities.dart'; +import '../utils/version_compatibility.dart'; final packagesDir = p.relative('../fixtures/_test', from: p.current); @@ -108,5 +110,11 @@ void main() { expect(newResult, isNotNull); }); }); - }); + // TODO(https://github.com/dart-lang/webdev/issues/1818): Re-enable. Not sure + // why this is passing locally but failing during CI tests. + }, + skip: !supportedMode( + compilationMode: CompilationMode.frontendServer, + nullSafetyMode: NullSafety.weak, + )); } diff --git a/dwds/test/readers/proxy_server_asset_reader_test.dart b/dwds/test/readers/proxy_server_asset_reader_test.dart index 303343fed..53d6f3bec 100644 --- a/dwds/test/readers/proxy_server_asset_reader_test.dart +++ b/dwds/test/readers/proxy_server_asset_reader_test.dart @@ -6,16 +6,16 @@ import 'package:dwds/src/readers/proxy_server_asset_reader.dart'; import 'package:test/test.dart'; import '../fixtures/context.dart'; +import '../utils/version_compatibility.dart'; void main() { - final context = TestContext(); - late ProxyServerAssetReader assetReader; - setUpAll(() async { - await context.setUp(); - assetReader = context.testServer.assetReader as ProxyServerAssetReader; - }); - group('ProxyServerAssetReader', () { + final context = TestContext(nullSafety: NullSafety.weak); + late ProxyServerAssetReader assetReader; + setUpAll(() async { + await context.setUp(); + assetReader = context.testServer.assetReader as ProxyServerAssetReader; + }); test('returns null if the dart path does not exist', () async { final result = await assetReader.dartSourceContents('some/path/foo.dart'); expect(result, isNull); @@ -38,5 +38,9 @@ void main() { .dartSourceContents('hello_world/foo.unsound.ddc.js.map'); expect(result, isNull); }); - }); + }, + // TODO(https://github.com/dart-lang/webdev/issues/1818) Re-enable. + skip: !supportedMode( + compilationMode: CompilationMode.frontendServer, + nullSafetyMode: NullSafety.weak)); } diff --git a/dwds/test/reload_test.dart b/dwds/test/reload_test.dart index 7ec5894cb..76db65f28 100644 --- a/dwds/test/reload_test.dart +++ b/dwds/test/reload_test.dart @@ -207,7 +207,9 @@ void main() { final source = await context.webDriver.pageSource; // Main is re-invoked which shouldn't clear the state. expect(source, contains('Hello World!')); - }); + // TODO(https://github.com/dart-lang/webdev/issues/1818): Re-enable. The + // callback passed to registerExtension requires a non-null return type. + }, skip: 'https://github.com/dart-lang/webdev/issues/1818'); test('can refresh the page via the fullReload service extension', () async { final client = context.debugConnection.vmService; diff --git a/dwds/test/utils/version_compatibility.dart b/dwds/test/utils/version_compatibility.dart new file mode 100644 index 000000000..1ff63ae81 --- /dev/null +++ b/dwds/test/utils/version_compatibility.dart @@ -0,0 +1,28 @@ +// Copyright (c) 2022, 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 'dart:io'; + +import 'package:pub_semver/pub_semver.dart'; + +import '../fixtures/context.dart'; + +bool supportedMode( + {required CompilationMode compilationMode, + required NullSafety nullSafetyMode}) { + final isDart3 = Version.parse(Platform.version.split(' ')[0]).major == 3; + // TODO(https://github.com/dart-lang/webdev/issues/1818): Support compiling to + // to weak null-safety for both FrontendServer and BuildDaemon. + if (isDart3 && nullSafetyMode == NullSafety.weak) { + return false; + } + // TODO(https://github.com/dart-lang/webdev/issues/1591): Support compiling to + // sound null-safety for the FrontendServer. + if (compilationMode == CompilationMode.frontendServer && + nullSafetyMode == NullSafety.sound) { + return false; + } + // All other modes are supported. + return true; +} diff --git a/fixtures/_testCircular1Sound/pubspec.yaml b/fixtures/_testCircular1Sound/pubspec.yaml index 5b6386c18..6a5741a6f 100644 --- a/fixtures/_testCircular1Sound/pubspec.yaml +++ b/fixtures/_testCircular1Sound/pubspec.yaml @@ -8,7 +8,7 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: - intl: ^0.16.0 + intl: ^0.17.0 path: ^1.6.1 _test_circular2_sound: path: ../_testCircular2Sound diff --git a/frontend_server_common/pubspec.yaml b/frontend_server_common/pubspec.yaml index 1d063dfa4..37ba0110e 100644 --- a/frontend_server_common/pubspec.yaml +++ b/frontend_server_common/pubspec.yaml @@ -15,4 +15,5 @@ dependencies: shelf: ^1.1.4 package_config: ^2.0.0 path: ^1.8.0 + pub_semver: ^2.1.1 usage: ^4.0.0