anchor.diff:    }
   }
   
  -extension on CheckTarget<CompletionGetSuggestionDetails2Result> {
  -  @useResult
  -  CheckTarget<SourceChange> get change {
  -    return nest(
  -      value.change,
  -      (selected) => 'has change ${valueStr(selected)}',
  -    );
  -  }
  -
  -  @useResult
  -  CheckTarget<String> get completion {
  -    return nest(
  -      value.completion,
  -      (selected) => 'has completion ${valueStr(selected)}',
  -    );
  +class _SuggestionDetailsPrinter {
  +  final StringBuffer buffer;
  +  final CompletionGetSuggestionDetails2Result result;
  +  final ResourceProvider resourceProvider;
  +  final Map<File, String> fileDisplayMap;
  +
  +  String _indent = '';
  +
  +  _SuggestionDetailsPrinter({
  +    required this.buffer,
  +    required this.result,
  +    required this.resourceProvider,
  +    required this.fileDisplayMap,
  +  });
  +
  +  void writeResult() {
  +    _writelnWithIndent('completion: ${result.completion}');
  +    _withIndent(() {
  +      _writeChange(result.change);
  +    });
  +  }
  +
  +  void _withIndent(void Function() f) {
  +    var indent = _indent;
  +    _indent = '$_indent  ';
  +    f();
  +    _indent = indent;
  +  }
  +
  +  void _writeChange(SourceChange change) {
  +    _writelnWithIndent('change');
  +    _withIndent(() {
  +      for (final fileEdit in change.edits) {
  +        _writeSourceFileEdit(fileEdit);
  +      }
  +    });
  +  }
  +
  +  void _writelnWithIndent(String line) {
  +    buffer.write(_indent);
  +    buffer.writeln(line);
  +  }
  +
  +  void _writeSourceEdit(SourceEdit edit) {
  +    _writelnWithIndent('offset: ${edit.offset}');
  +    _writelnWithIndent('length: ${edit.length}');
  +
  +    final replacementStr = edit.replacement.replaceAll('\n', r'\n');
  +    _writelnWithIndent('replacement: $replacementStr');
  +  }
  +
  +  void _writeSourceFileEdit(SourceFileEdit fileEdit) {
  +    final file = resourceProvider.getFile(fileEdit.file);
  +    final fileStr = fileDisplayMap[file] ?? fail('No display name: $file');
  +    _writelnWithIndent(fileStr);
  +
  +    _withIndent(() {
  +      for (final edit in fileEdit.edits) {
  +        _writeSourceEdit(edit);
  +      }
  +    });
     }
   }
   
  
positive.code:   R^
  }
  ''', completion: 'Random', libraryUri: 'dart:math');
      check(details)
        ..completion.isEqualTo('Random')
        ..change
            .hasFileEdit(testFile.path)
            .appliedTo(testFileContent)
            .isEqualTo(r'''
  import 'dart:math';
  
  void f() {
    R
  }
  ''');
    }
  
  
negative.code: import 'package:analysis_server/src/plugin/plugin_manager.dart';
  import 'package:analysis_server/src/protocol_server.dart';
  import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
  import 'package:analyzer/file_system/file_system.dart';
  import 'package:analyzer/instrumentation/service.dart';
  import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
  import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
  import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
  import 'package:test/test.dart';
  import 'package:test_reflective_loader/test_reflective_loader.dart';
  
  