// Copyright (c) 2020, 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.

@TestOn('vm')
library;

import 'package:_test_common/package_graphs.dart';
import 'package:build/build.dart';
import 'package:build_config/build_config.dart';
import 'package:build_runner_core/build_runner_core.dart';
import 'package:build_runner_core/src/package_graph/target_graph.dart';
import 'package:glob/glob.dart';
import 'package:logging/logging.dart';
import 'package:package_config/package_config.dart';
import 'package:test/test.dart';

void main() {
  group('TargetGraph.forPackageGraph', () {
    test('warns if required sources are missing', () {
      var logs = <LogRecord>[];
      var listener = Logger.root.onRecord.listen(logs.add);
      addTearDown(listener.cancel);

      var packageB = PackageNode(
          'b', '/fakeB', DependencyType.path, LanguageVersion(0, 0));
      var packageA = PackageNode(
          'a', '/fakeA', DependencyType.path, LanguageVersion(0, 0),
          isRoot: true)
        ..dependencies.add(packageB);
      var packageGraph = PackageGraph.fromRoot(packageA);

      TargetGraph.forPackageGraph(packageGraph, defaultRootPackageSources: [
        '**'
      ], overrideBuildConfig: {
        'a': BuildConfig.fromMap('a', [
          'b'
        ], {
          'targets': {
            r'$default': {
              'sources': ['lib/**']
            }
          }
        }),
        'b': BuildConfig.fromMap('b', [], {
          'targets': {
            r'$default': {
              'sources': ['web/**']
            }
          }
        }),
      }, requiredSourcePaths: [
        r'lib/$lib$',
      ], requiredRootSourcePaths: [
        r'lib/$lib$',
        r'$package$'
      ]);

      expect(
          logs,
          containsAll([
            isA<LogRecord>()
                .having((r) => r.level, 'level', equals(Level.WARNING))
                .having(
                    (r) => r.message,
                    'message',
                    allOf(
                        contains(
                            'The package `a` does not include some required '
                            'sources in any of its targets'),
                        contains(r'$package$'),
                        isNot(contains(r'lib/$lib$')))),
            isA<LogRecord>()
                .having((r) => r.level, 'level', equals(Level.WARNING))
                .having(
                    (r) => r.message,
                    'message',
                    allOf(
                        contains(
                            'The package `b` does not include some required '
                            'sources in any of its targets'),
                        contains(r'lib/$lib$'),
                        isNot(contains(r'$package$')))),
          ]));
    });
  });

  group('target graph reports visible assets', () {
    final a = rootPackage('a');
    final b = package('b');
    final packages = buildPackageGraph({
      a: ['b'],
      b: []
    });

    test('for root package', () async {
      final targetGraph = await TargetGraph.forPackageGraph(packages,
          defaultRootPackageSources: ['**']);

      expect(targetGraph.isVisibleInBuild(AssetId('a', 'web/index.html'), a),
          isTrue);
      expect(
          targetGraph.isVisibleInBuild(AssetId('a', 'lib/a.dart'), a), isTrue);
      expect(targetGraph.isVisibleInBuild(AssetId('a', 'test/my_test.dart'), a),
          isTrue);
      expect(targetGraph.validInputsFor(a), ['**/*']);
    });

    test('for non-root package with default configuration', () async {
      final targetGraph = await TargetGraph.forPackageGraph(packages,
          defaultRootPackageSources: ['**']);

      expect(targetGraph.isVisibleInBuild(AssetId('b', 'web/index.html'), b),
          isFalse);
      expect(
          targetGraph.isVisibleInBuild(AssetId('b', 'lib/b.dart'), b), isTrue);
      expect(
          targetGraph.isVisibleInBuild(AssetId('b', 'LICENSE.txt'), b), isTrue);
      expect(targetGraph.isVisibleInBuild(AssetId('b', 'README'), b), isTrue);
      expect(targetGraph.isVisibleInBuild(AssetId('b', 'test/my_test.dart'), b),
          isFalse);

      expect(targetGraph.validInputsFor(b), contains('lib/**'));
    });

    test('for non-root package exposing additional assets', () async {
      final targetGraph = await TargetGraph.forPackageGraph(packages,
          defaultRootPackageSources: [
            '**'
          ],
          overrideBuildConfig: {
            'b': BuildConfig.parse(
                'b', [], 'additional_public_assets: ["test/**"]'),
          });

      expect(
          targetGraph.isVisibleInBuild(AssetId('b', 'lib/b.dart'), b), isTrue);
      expect(targetGraph.isVisibleInBuild(AssetId('b', 'test/my_test.dart'), b),
          isTrue);

      expect(targetGraph.validInputsFor(b), contains('test/**'));
      // The additional input should also be included in the default target
      expect(targetGraph.allModules['b:b']!.sourceIncludes,
          contains(isA<Glob>().having((e) => e.pattern, 'pattern', 'test/**')));
    });
  });
}
