// 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 'dart:convert';

import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;

import '../../io.dart';

void main() {
  setUpAll(precompileTestExecutable);

  test('shuffles test order when passed a seed', () async {
    await d.file('test.dart', '''
      import 'package:test/test.dart';

      void main() {
        test("test 1", () {});
        test("test 2", () {});
        test("test 3", () {});
        test("test 4", () {});
      }
    ''').create();

    // Test with a given seed
    var test = await runTest([
      'test.dart',
      '--test-randomize-ordering-seed=987654',
    ]);
    expect(
      test.stdout,
      containsInOrder([
        '+0: test 4',
        '+1: test 3',
        '+2: test 1',
        '+3: test 2',
        '+4: All tests passed!',
      ]),
    );
    await test.shouldExit(0);

    // Do not shuffle when passed 0
    test = await runTest(['test.dart', '--test-randomize-ordering-seed=0']);
    expect(
      test.stdout,
      containsInOrder([
        '+0: test 1',
        '+1: test 2',
        '+2: test 3',
        '+3: test 4',
        '+4: All tests passed!',
      ]),
    );
    await test.shouldExit(0);

    // Do not shuffle when passed nothing
    test = await runTest(['test.dart']);
    expect(
      test.stdout,
      containsInOrder([
        '+0: test 1',
        '+1: test 2',
        '+2: test 3',
        '+3: test 4',
        '+4: All tests passed!',
      ]),
    );
    await test.shouldExit(0);

    // Shuffle when passed random
    test = await runTest([
      'test.dart',
      '--test-randomize-ordering-seed=random',
    ]);
    expect(
      test.stdout,
      emitsInAnyOrder([
        contains('Shuffling test order with --test-randomize-ordering-seed'),
        isNot(
          contains(
            'Shuffling test order with --test-randomize-ordering-seed=0',
          ),
        ),
      ]),
    );
    await test.shouldExit(0);

    // Doesn't log about shuffling with the json reporter
    test = await runTest([
      'test.dart',
      '--test-randomize-ordering-seed=random',
      '-r',
      'json',
    ]);
    expect(test.stdout, neverEmits(contains('Shuffling test order')));
    await test.shouldExit(0);
  });

  test('test shuffling can be disabled in dart_test.yml', () async {
    await d
        .file(
          'dart_test.yaml',
          jsonEncode({
            'tags': {
              'doNotShuffle': {'allow_test_randomization': false},
            },
          }),
        )
        .create();

    await d.file('test.dart', '''
      @Tags(['doNotShuffle'])
      import 'package:test/test.dart';

      void main() {
        test("test 1", () {});
        test("test 2", () {});
        test("test 3", () {});
        test("test 4", () {});
      }
    ''').create();

    var test = await runTest([
      'test.dart',
      '--test-randomize-ordering-seed=987654',
    ]);
    expect(
      test.stdout,
      containsInOrder([
        '+0: test 1',
        '+1: test 2',
        '+2: test 3',
        '+3: test 4',
        '+4: All tests passed!',
      ]),
    );
    await test.shouldExit(0);
  });

  test('shuffles each suite with the same seed', () async {
    await d.file('1_test.dart', '''
      import 'package:test/test.dart';

      void main() {
        test("test 1.1", () {});
        test("test 1.2", () {});
        test("test 1.3", () {});
      }
    ''').create();

    await d.file('2_test.dart', '''
      import 'package:test/test.dart';

      void main() {
        test("test 2.1", () {});
        test("test 2.2", () {});
        test("test 2.3", () {});
      }
    ''').create();

    var test = await runTest(['.', '--test-randomize-ordering-seed=12345']);
    expect(
      test.stdout,
      emitsInAnyOrder([
        containsInOrder([
          './1_test.dart: test 1.2',
          './1_test.dart: test 1.3',
          './1_test.dart: test 1.1',
        ]),
        containsInOrder([
          './2_test.dart: test 2.2',
          './2_test.dart: test 2.3',
          './2_test.dart: test 2.1',
        ]),
        contains('+6: All tests passed!'),
      ]),
    );
    await test.shouldExit(0);
  });

  test('shuffles groups as well as tests in groups', () async {
    await d.file('test.dart', '''
      import 'package:test/test.dart';

      void main() {
      group("Group 1", () {
        test("test 1.1", () {});
        test("test 1.2", () {});
        test("test 1.3", () {});
        test("test 1.4", () {});
       });
      group("Group 2", () {
        test("test 2.1", () {});
        test("test 2.2", () {});
        test("test 2.3", () {});
        test("test 2.4", () {});
       });
      }
    ''').create();

    // Test with a given seed
    var test = await runTest([
      'test.dart',
      '--test-randomize-ordering-seed=123',
    ]);
    expect(
      test.stdout,
      containsInOrder([
        '+0: Group 2 test 2.4',
        '+1: Group 2 test 2.2',
        '+2: Group 2 test 2.1',
        '+3: Group 2 test 2.3',
        '+4: Group 1 test 1.4',
        '+5: Group 1 test 1.2',
        '+6: Group 1 test 1.1',
        '+7: Group 1 test 1.3',
        '+8: All tests passed!',
      ]),
    );
    await test.shouldExit(0);
  });

  test('shuffles nested groups', () async {
    await d.file('test.dart', '''
      import 'package:test/test.dart';

      void main() {
      group("Group 1", () {
        test("test 1.1", () {});
        test("test 1.2", () {});
        group("Group 2", () {
          test("test 2.3", () {});
          test("test 2.4", () {});
        });
       });
      }
    ''').create();

    var test = await runTest([
      'test.dart',
      '--test-randomize-ordering-seed=123',
    ]);
    expect(
      test.stdout,
      containsInOrder([
        '+0: Group 1 test 1.1',
        '+1: Group 1 Group 2 test 2.4',
        '+2: Group 1 Group 2 test 2.3',
        '+3: Group 1 test 1.2',
        '+4: All tests passed!',
      ]),
    );
    await test.shouldExit(0);
  });
}
