// Copyright 2014 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:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {

  test('ButtonBarThemeData null fields by default', () {
    const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData();
    expect(buttonBarTheme.alignment, null);
    expect(buttonBarTheme.mainAxisSize, null);
    expect(buttonBarTheme.buttonTextTheme, null);
    expect(buttonBarTheme.buttonMinWidth, null);
    expect(buttonBarTheme.buttonHeight, null);
    expect(buttonBarTheme.buttonPadding, null);
    expect(buttonBarTheme.buttonAlignedDropdown, null);
    expect(buttonBarTheme.layoutBehavior, null);
    expect(buttonBarTheme.overflowDirection, null);
  });

  test('ThemeData uses default ButtonBarThemeData', () {
    expect(ThemeData().buttonBarTheme, equals(const ButtonBarThemeData()));
  });

  test('ButtonBarThemeData copyWith, ==, hashCode basics', () {
    expect(const ButtonBarThemeData(), const ButtonBarThemeData().copyWith());
    expect(const ButtonBarThemeData().hashCode, const ButtonBarThemeData().copyWith().hashCode);
  });

  testWidgets('ButtonBarThemeData lerps correctly', (WidgetTester tester) async {
    const ButtonBarThemeData barThemePrimary = ButtonBarThemeData(
      alignment: MainAxisAlignment.end,
      mainAxisSize: MainAxisSize.min,
      buttonTextTheme: ButtonTextTheme.primary,
      buttonMinWidth: 20.0,
      buttonHeight: 20.0,
      buttonPadding: EdgeInsets.symmetric(vertical: 5.0),
      buttonAlignedDropdown: false,
      layoutBehavior: ButtonBarLayoutBehavior.padded,
      overflowDirection: VerticalDirection.down,
    );
    const ButtonBarThemeData barThemeAccent = ButtonBarThemeData(
      alignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.max,
      buttonTextTheme: ButtonTextTheme.accent,
      buttonMinWidth: 10.0,
      buttonHeight: 40.0,
      buttonPadding: EdgeInsets.symmetric(horizontal: 10.0),
      buttonAlignedDropdown: true,
      layoutBehavior: ButtonBarLayoutBehavior.constrained,
      overflowDirection: VerticalDirection.up,
    );

    final ButtonBarThemeData lerp = ButtonBarThemeData.lerp(barThemePrimary, barThemeAccent, 0.5);
    expect(lerp.alignment, equals(MainAxisAlignment.center));
    expect(lerp.mainAxisSize, equals(MainAxisSize.max));
    expect(lerp.buttonTextTheme, equals(ButtonTextTheme.accent));
    expect(lerp.buttonMinWidth, equals(15.0));
    expect(lerp.buttonHeight, equals(30.0));
    expect(lerp.buttonPadding, equals(const EdgeInsets.fromLTRB(5.0, 2.5, 5.0, 2.5)));
    expect(lerp.buttonAlignedDropdown, isTrue);
    expect(lerp.layoutBehavior, equals(ButtonBarLayoutBehavior.constrained));
    expect(lerp.overflowDirection, equals(VerticalDirection.up));
  });

  testWidgets('Default ButtonBarThemeData debugFillProperties', (WidgetTester tester) async {
    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
    const ButtonBarThemeData().debugFillProperties(builder);

    final List<String> description = builder.properties
        .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
        .map((DiagnosticsNode node) => node.toString())
        .toList();

    expect(description, <String>[]);
  });

  testWidgets('ButtonBarThemeData implements debugFillProperties', (WidgetTester tester) async {
    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
    const ButtonBarThemeData(
      alignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.max,
      buttonTextTheme: ButtonTextTheme.accent,
      buttonMinWidth: 10.0,
      buttonHeight: 42.0,
      buttonPadding: EdgeInsets.symmetric(horizontal: 7.3),
      buttonAlignedDropdown: true,
      layoutBehavior: ButtonBarLayoutBehavior.constrained,
      overflowDirection: VerticalDirection.up,
    ).debugFillProperties(builder);

    final List<String> description = builder.properties
        .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
        .map((DiagnosticsNode node) => node.toString())
        .toList();

    expect(description, <String>[
      'alignment: MainAxisAlignment.center',
      'mainAxisSize: MainAxisSize.max',
      'textTheme: ButtonTextTheme.accent',
      'minWidth: 10.0',
      'height: 42.0',
      'padding: EdgeInsets(7.3, 0.0, 7.3, 0.0)',
      'dropdown width matches button',
      'layoutBehavior: ButtonBarLayoutBehavior.constrained',
      'overflowDirection: VerticalDirection.up',
    ]);
  });

  testWidgets('ButtonBarTheme.of falls back to ThemeData.buttonBarTheme', (WidgetTester tester) async {
    const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0);
    BuildContext capturedContext;
    await tester.pumpWidget(
      MaterialApp(
        theme: ThemeData(buttonBarTheme: buttonBarTheme),
        home: Builder(
          builder: (BuildContext context) {
            capturedContext = context;
            return Container();
          }
        ),
      ),
    );
    expect(ButtonBarTheme.of(capturedContext), equals(buttonBarTheme));
    expect(ButtonBarTheme.of(capturedContext).buttonMinWidth, equals(42.0));
  });

  testWidgets('ButtonBarTheme overrides ThemeData.buttonBarTheme', (WidgetTester tester) async {
    const ButtonBarThemeData defaultBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0);
    const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 84.0);
    BuildContext capturedContext;
    await tester.pumpWidget(
      MaterialApp(
        theme: ThemeData(buttonBarTheme: defaultBarTheme),
        home: Builder(
          builder: (BuildContext context) {
            return ButtonBarTheme(
              data: buttonBarTheme,
              child: Builder(
                builder: (BuildContext context) {
                  capturedContext = context;
                  return Container();
                },
              ),
            );
          }
        ),
      ),
    );
    expect(ButtonBarTheme.of(capturedContext), equals(buttonBarTheme));
    expect(ButtonBarTheme.of(capturedContext).buttonMinWidth, equals(84.0));
  });
}
