From 771a07bfe9e8df8214ddd0eae579e79dba8c298e Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Wed, 15 May 2024 16:38:29 -0700 Subject: [PATCH] Include stdout on a failed gn desc call. --- tools/engine_tool/lib/src/gn.dart | 12 ++- tools/engine_tool/test/gn_test.dart | 112 ++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 tools/engine_tool/test/gn_test.dart diff --git a/tools/engine_tool/lib/src/gn.dart b/tools/engine_tool/lib/src/gn.dart index 986c47c20a04a..b8812dffc7194 100644 --- a/tools/engine_tool/lib/src/gn.dart +++ b/tools/engine_tool/lib/src/gn.dart @@ -67,7 +67,7 @@ interface class Gn { result = JsonObject.parse(process.stdout); } on FormatException catch (e) { _environment.logger.fatal( - 'Failed to parse JSON output from `gn desc`:\n$e', + 'Failed to parse JSON output from `gn desc`:\n$e\n${process.stdout}', ); } @@ -136,6 +136,10 @@ sealed class BuildTarget { @mustBeOverridden @override int get hashCode; + + @mustBeOverridden + @override + String toString(); } /// A build target that produces a [shared library][] or [static library][]. @@ -158,6 +162,9 @@ final class LibraryBuildTarget extends BuildTarget { @override int get hashCode => Object.hash(label, testOnly); + + @override + String toString() => 'LibraryBuildTarget($label, testOnly=$testOnly)'; } /// A build target that produces an [executable][] program. @@ -184,4 +191,7 @@ final class ExecutableBuildTarget extends BuildTarget { @override int get hashCode => Object.hash(label, testOnly, executable); + + @override + String toString() => 'ExecutableBuildTarget($label, testOnly=$testOnly, executable=$executable)'; } diff --git a/tools/engine_tool/test/gn_test.dart b/tools/engine_tool/test/gn_test.dart new file mode 100644 index 0000000000000..8bebbd335c7ab --- /dev/null +++ b/tools/engine_tool/test/gn_test.dart @@ -0,0 +1,112 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:engine_tool/src/gn.dart'; +import 'package:engine_tool/src/label.dart'; +import 'package:litetest/litetest.dart'; + +import 'utils.dart'; + +void main() { + test('gn.desc handles a non-zero exit code', () async { + final TestEnvironment testEnv = TestEnvironment.withTestEngine( + cannedProcesses: [ + CannedProcess( + (List command) => command.contains('desc'), + exitCode: 1, + stdout: 'stdout', + stderr: 'stderr', + ), + ], + ); + try { + final Gn gn = Gn.fromEnvironment(testEnv.environment); + await gn.desc('out/Release', TargetPattern('//foo', 'bar')); + fail('Expected an exception'); + } catch (e) { + final String message = '$e'; + expect(message, contains('Failed to run')); + expect(message, contains('exit code 1')); + expect(message, contains('STDOUT:\nstdout')); + expect(message, contains('STDERR:\nstderr')); + } finally { + testEnv.cleanup(); + } + }); + + test('gn.desc handles unparseable stdout', () async { + final TestEnvironment testEnv = TestEnvironment.withTestEngine( + cannedProcesses: [ + CannedProcess( + (List command) => command.contains('desc'), + stdout: 'not json', + ), + ], + ); + try { + final Gn gn = Gn.fromEnvironment(testEnv.environment); + await gn.desc('out/Release', TargetPattern('//foo', 'bar')); + fail('Expected an exception'); + } catch (e) { + final String message = '$e'; + expect(message, contains('Failed to parse JSON')); + expect(message, contains('not json')); + } finally { + testEnv.cleanup(); + } + }); + + test('gn.desc parses build targets', () async { + final TestEnvironment testEnv = TestEnvironment.withTestEngine( + cannedProcesses: [ + CannedProcess( + (List command) => command.contains('desc'), + stdout: ''' + { + "//foo/bar:baz_test": { + "outputs": ["//out/host_debug/foo/bar/baz_test"], + "testonly": true, + "type": "executable" + }, + "//foo/bar:baz_shared_library": { + "testonly": false, + "type": "shared_library" + }, + "//foo/bar:baz_static_library": { + "testonly": false, + "type": "static_library" + } + } + ''', + ), + ], + ); + try { + final Gn gn = Gn.fromEnvironment(testEnv.environment); + final List targets = await gn.desc('out/Release', TargetPattern('//foo', 'bar')); + expect(targets, hasLength(3)); + + // There should be exactly one binary test target and two library targets. + final ExecutableBuildTarget testTarget = targets.whereType().single; + expect(testTarget, ExecutableBuildTarget( + label: Label('//foo/bar', 'baz_test'), + testOnly: true, + executable: 'out/host_debug/foo/bar/baz_test', + )); + + final List libraryTargets = targets.whereType().toList(); + expect(libraryTargets, hasLength(2)); + expect(libraryTargets.contains(LibraryBuildTarget( + label: Label('//foo/bar', 'baz_shared_library'), + testOnly: false, + )), isTrue); + expect(libraryTargets.contains(LibraryBuildTarget( + label: Label('//foo/bar', 'baz_static_library'), + testOnly: false, + )), isTrue); + } finally { + testEnv.cleanup(); + } + }); +}