// Copyright (c) 2021, 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 'package:code_builder/code_builder.dart';
import 'package:test/test.dart';

import '../common.dart';

void main() {
  useDartfmt();

  test('should create a mixin', () {
    expect(
      Mixin((b) => b..name = 'Foo'),
      equalsDart(r'''
        mixin Foo {}
      '''),
    );
  });

  test('should create a base mixin', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Foo'
              ..base = true,
      ),
      equalsDart(r'''
        base mixin Foo {}
      '''),
    );
  });

  test('should create a mixin with documentations', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Foo'
              ..docs.addAll(const ['/// My favorite mixin.']),
      ),
      equalsDart(r'''
        /// My favorite mixin.
        mixin Foo {}
      '''),
    );
  });

  test('should create a mixin with annotations', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Foo'
              ..annotations.addAll([
                refer('deprecated'),
                refer(
                  'Deprecated',
                ).call([literalString('This is an old mixin')]),
              ]),
      ),
      equalsDart(r'''
        @deprecated
        @Deprecated('This is an old mixin')
        mixin Foo {}
      '''),
    );
  });

  test('should create a mixin with a generic type', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'List'
              ..types.add(refer('T')),
      ),
      equalsDart(r'''
        mixin List<T> {}
      '''),
    );
  });

  test('should create a mixin with multiple generic types', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Map'
              ..types.addAll([refer('K'), refer('V')]),
      ),
      equalsDart(r'''
        mixin Map<K, V> {}
      '''),
    );
  });

  test('should create a mixin with a bound generic type', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Comparable'
              ..types.add(
                TypeReference(
                  (b) =>
                      b
                        ..symbol = 'T'
                        ..bound = TypeReference(
                          (b) =>
                              b
                                ..symbol = 'Comparable'
                                ..types.add(refer('T').type),
                        ),
                ),
              ),
      ),
      equalsDart(r'''
        mixin Comparable<T extends Comparable<T>> {}
      '''),
    );
  });

  test('should create a mixin on another mixin', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Foo'
              ..on = TypeReference((b) => b.symbol = 'Bar'),
      ),
      equalsDart(r'''
        mixin Foo on Bar {}
      '''),
    );
  });

  test('should create a mixin implementing another mixin', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Foo'
              ..on = TypeReference((b) => b.symbol = 'Bar')
              ..implements.add(TypeReference((b) => b.symbol = 'Foo')),
      ),
      equalsDart(r'''
        mixin Foo on Bar implements Foo {}
      '''),
    );
  });

  test('should create a mixin with a method', () {
    expect(
      Mixin(
        (b) =>
            b
              ..name = 'Foo'
              ..methods.add(
                Method(
                  (b) =>
                      b
                        ..name = 'foo'
                        ..body = const Code('return 1+ 2;'),
                ),
              ),
      ),
      equalsDart(r'''
        mixin Foo {
          foo() {
            return 1 + 2;
          }
        }
      '''),
    );
  });
}
