// Copyright (c) 2018, 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:convert'; import 'package:checked_yaml/checked_yaml.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:pubspec_parse/pubspec_parse.dart'; import 'package:stack_trace/stack_trace.dart'; import 'package:test/test.dart'; import 'pub_utils.dart'; const defaultPubspec = { 'name': 'sample', 'environment': {'sdk': '>=2.12.0 <3.0.0'}, }; String _encodeJson(Object? input) => const JsonEncoder.withIndent(' ').convert(input); Matcher _throwsParsedYamlException(String prettyValue) => throwsA( const TypeMatcher().having( (e) { final message = e.formattedMessage; printOnFailure("Actual error format:\nr'''\n$message'''"); _printDebugParsedYamlException(e); return message; }, 'formattedMessage', prettyValue, ), ); void _printDebugParsedYamlException(ParsedYamlException e) { var innerError = e.innerError; StackTrace? innerStack; if (innerError is CheckedFromJsonException) { final cfje = innerError; if (cfje.innerError != null) { innerError = cfje.innerError; innerStack = cfje.innerStack; } } if (innerError != null) { final items = [innerError]; if (innerStack != null) { items.add(Trace.format(innerStack)); } final content = LineSplitter.split(items.join('\n')).map((e) => ' $e').join('\n'); printOnFailure('Inner error details:\n$content'); } } Future parse( Object? content, { bool quietOnError = false, bool skipTryPub = false, bool lenient = false, }) async { final encoded = _encodeJson(content); ProcResult? pubResult; if (!skipTryPub) { // ignore: deprecated_member_use pubResult = await tryPub(encoded); expect(pubResult, isNotNull); } try { final value = Pubspec.parse(encoded, lenient: lenient); if (pubResult != null) { addTearDown(() { expect( pubResult!.cleanParse, isTrue, reason: 'On success, parsing from the pub client should also succeed.', ); }); } return value; } catch (e) { if (pubResult != null) { addTearDown(() { expect( pubResult!.cleanParse, isFalse, reason: 'On failure, parsing from the pub client should also fail.', ); }); } if (e is ParsedYamlException) { if (!quietOnError) { _printDebugParsedYamlException(e); } } rethrow; } } void expectParseThrows( Object? content, String expectedError, { bool skipTryPub = false, bool lenient = false, }) => expect( () => parse( content, lenient: lenient, quietOnError: true, skipTryPub: skipTryPub, ), _throwsParsedYamlException(expectedError), ); void expectParseThrowsContaining( Object? content, String errorFragment, { bool skipTryPub = false, bool lenient = false, }) { expect( () => parse( content, lenient: lenient, quietOnError: true, skipTryPub: skipTryPub, ), _throwsParsedYamlExceptionContaining(errorFragment), ); } // ignore: prefer_expression_function_bodies Matcher _throwsParsedYamlExceptionContaining(String errorFragment) { return throwsA( const TypeMatcher().having( (e) { final message = e.formattedMessage; printOnFailure("Actual error format:\nr'''\n$message'''"); _printDebugParsedYamlException(e); return message; }, 'formattedMessage', contains(errorFragment), ), ); }