// Copyright (c) 2016, 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:boolean_selector/boolean_selector.dart';
import 'package:test/test.dart';
import 'package:test_api/src/backend/platform_selector.dart';
import 'package:test_api/src/backend/runtime.dart';
import 'package:test_core/src/runner/compiler_selection.dart';
import 'package:test_core/src/runner/runtime_selection.dart';

import '../../utils.dart';

void main() {
  group('merge', () {
    group('for most fields', () {
      test('if neither is defined, preserves the default', () {
        var merged = suiteConfiguration().merge(suiteConfiguration());
        expect(merged.jsTrace, isFalse);
        expect(merged.runSkipped, isFalse);
        expect(merged.precompiledPath, isNull);
        expect(merged.runtimes, equals([Runtime.vm.identifier]));
        expect(merged.compilerSelections, isNull);
      });

      test("if only the old configuration's is defined, uses it", () {
        var merged = suiteConfiguration(
          jsTrace: true,
          runSkipped: true,
          precompiledPath: '/tmp/js',
          runtimes: [RuntimeSelection(Runtime.chrome.identifier)],
          compilerSelections: [CompilerSelection.parse('dart2js')],
        ).merge(suiteConfiguration());

        expect(merged.jsTrace, isTrue);
        expect(merged.runSkipped, isTrue);
        expect(merged.precompiledPath, equals('/tmp/js'));
        expect(merged.runtimes, equals([Runtime.chrome.identifier]));
        expect(
          merged.compilerSelections,
          equals([CompilerSelection.parse('dart2js')]),
        );
      });

      test("if only the configuration's is defined, uses it", () {
        var merged = suiteConfiguration().merge(
          suiteConfiguration(
            jsTrace: true,
            runSkipped: true,
            precompiledPath: '/tmp/js',
            runtimes: [RuntimeSelection(Runtime.chrome.identifier)],
            compilerSelections: [CompilerSelection.parse('dart2js')],
          ),
        );

        expect(merged.jsTrace, isTrue);
        expect(merged.runSkipped, isTrue);
        expect(merged.precompiledPath, equals('/tmp/js'));
        expect(merged.runtimes, equals([Runtime.chrome.identifier]));
        expect(
          merged.compilerSelections,
          equals([CompilerSelection.parse('dart2js')]),
        );
      });

      test("if the two configurations conflict, uses the configuration's "
          'values', () {
        var older = suiteConfiguration(
          jsTrace: false,
          runSkipped: true,
          precompiledPath: '/tmp/js',
          runtimes: [RuntimeSelection(Runtime.chrome.identifier)],
          compilerSelections: [CompilerSelection.parse('dart2js')],
        );
        var newer = suiteConfiguration(
          jsTrace: true,
          runSkipped: false,
          precompiledPath: '../js',
          runtimes: [RuntimeSelection(Runtime.firefox.identifier)],
          compilerSelections: [CompilerSelection.parse('source')],
        );
        var merged = older.merge(newer);

        expect(merged.jsTrace, isTrue);
        expect(merged.runSkipped, isFalse);
        expect(merged.precompiledPath, equals('../js'));
        expect(merged.runtimes, equals([Runtime.firefox.identifier]));
        expect(
          merged.compilerSelections,
          equals([CompilerSelection.parse('source')]),
        );
      });
    });

    group('for dart2jsArgs', () {
      test('if neither is defined, preserves the default', () {
        var merged = suiteConfiguration().merge(suiteConfiguration());
        expect(merged.dart2jsArgs, isEmpty);
      });

      test("if only the old configuration's is defined, uses it", () {
        var merged = suiteConfiguration(
          dart2jsArgs: ['--foo', '--bar'],
        ).merge(suiteConfiguration());
        expect(merged.dart2jsArgs, equals(['--foo', '--bar']));
      });

      test("if only the configuration's is defined, uses it", () {
        var merged = suiteConfiguration().merge(
          suiteConfiguration(dart2jsArgs: ['--foo', '--bar']),
        );
        expect(merged.dart2jsArgs, equals(['--foo', '--bar']));
      });

      test('if both are defined, concatenates them', () {
        var older = suiteConfiguration(dart2jsArgs: ['--foo', '--bar']);
        var newer = suiteConfiguration(dart2jsArgs: ['--baz']);
        var merged = older.merge(newer);
        expect(merged.dart2jsArgs, equals(['--foo', '--bar', '--baz']));
      });
    });

    group('for config maps', () {
      test('merges each nested configuration', () {
        var merged = suiteConfiguration(
          tags: {
            BooleanSelector.parse('foo'): suiteConfiguration(
              precompiledPath: 'path/',
            ),
            BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: true),
          },
          onPlatform: {
            PlatformSelector.parse('vm'): suiteConfiguration(
              precompiledPath: 'path/',
            ),
            PlatformSelector.parse('chrome'): suiteConfiguration(jsTrace: true),
          },
        ).merge(
          suiteConfiguration(
            tags: {
              BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: false),
              BooleanSelector.parse('baz'): suiteConfiguration(
                runSkipped: true,
              ),
            },
            onPlatform: {
              PlatformSelector.parse('chrome'): suiteConfiguration(
                jsTrace: false,
              ),
              PlatformSelector.parse('firefox'): suiteConfiguration(
                runSkipped: true,
              ),
            },
          ),
        );

        expect(
          merged.tags[BooleanSelector.parse('foo')]!.precompiledPath,
          equals('path/'),
        );
        expect(merged.tags[BooleanSelector.parse('bar')]!.jsTrace, isFalse);
        expect(merged.tags[BooleanSelector.parse('baz')]!.runSkipped, isTrue);

        expect(
          merged.onPlatform[PlatformSelector.parse('vm')]!.precompiledPath,
          'path/',
        );
        expect(
          merged.onPlatform[PlatformSelector.parse('chrome')]!.jsTrace,
          isFalse,
        );
        expect(
          merged.onPlatform[PlatformSelector.parse('firefox')]!.runSkipped,
          isTrue,
        );
      });
    });
  });
}
