Skip to content

Commit

Permalink
- initial tests for utils and theme
Browse files Browse the repository at this point in the history
  • Loading branch information
ps9310 committed Jun 10, 2024
1 parent 734e86b commit 1d6b080
Show file tree
Hide file tree
Showing 17 changed files with 2,836 additions and 64 deletions.
31 changes: 31 additions & 0 deletions coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

# Check if lcov is installed
if ! command -v lcov &> /dev/null
then
echo "lcov could not be found, please install it first."
exit
fi

# Run the tests with coverage
flutter test --coverage

# Generate the LCOV report
lcov --capture --directory coverage --output-file coverage/lcov.info

# Remove unnecessary files from the report
lcov --remove coverage/lcov.info 'lib/*/*.g.dart' 'lib/*/*.freezed.dart' -o coverage/lcov.info

# Generate the HTML report
genhtml coverage/lcov.info --output-directory coverage/html

# Open the coverage report in the default browser
if [ "$(uname)" == "Darwin" ]; then
open coverage/html/index.html
elif [ "$(uname)" == "Linux" ]; then
xdg-open coverage/html/index.html
elif [ "$(uname)" == "CYGWIN" ] || [ "$(uname)" == "MINGW32" ] || [ "$(uname)" == "MINGW64" ]; then
start coverage/html/index.html
fi

echo "Coverage report generated and opened in the default browser."
31 changes: 19 additions & 12 deletions lib/src/theme/color_swatch.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';

import 'color_extensions.dart';
Expand All @@ -6,7 +7,7 @@ import 'contrast.dart';

/// A swatch of colors with values from 10 (light) to 100 (dark).
@immutable
class ZetaColorSwatch extends ColorSwatch<int> {
class ZetaColorSwatch extends ColorSwatch<int> with EquatableMixin {
/// Constructs a [ZetaColorSwatch].
///
/// See also:
Expand Down Expand Up @@ -142,7 +143,8 @@ class ZetaColorSwatch extends ColorSwatch<int> {

/// Returns the color shade for a subtle visual element depending on the ZetaContrast value.
///
/// For both [ZetaContrast.aa] and [ZetaContrast.aaa], it returns 40.
/// For [ZetaContrast.aa], it returns 40.
/// For [ZetaContrast.aaa], it returns 60.
Color get subtle => shade(contrast.subtle);

/// Returns the color shade for a surface depending on the ZetaContrast value.
Expand Down Expand Up @@ -185,14 +187,19 @@ class ZetaColorSwatch extends ColorSwatch<int> {
}

@override
bool operator ==(Object other) =>
identical(this, other) ||
super == other &&
other is ZetaColorSwatch &&
runtimeType == other.runtimeType &&
brightness == other.brightness &&
contrast == other.contrast;

@override
int get hashCode => super.hashCode ^ brightness.hashCode ^ contrast.hashCode;
List<Object?> get props => [
super.value,
brightness,
contrast,
shade10,
shade20,
shade30,
shade40,
shade50,
shade60,
shade70,
shade80,
shade90,
shade100,
];
}
64 changes: 16 additions & 48 deletions lib/src/theme/colors.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';

import 'color_extensions.dart';
Expand All @@ -10,7 +11,7 @@ import 'contrast.dart';
///
/// A customizable, token-based color palette, adapting Zeta colors to Flutter's colorScheme.
@immutable
class ZetaColors {
class ZetaColors extends Equatable {
/// Default constructor for instance of [ZetaColors].
ZetaColors({
this.brightness = Brightness.light,
Expand Down Expand Up @@ -688,53 +689,20 @@ class ZetaColors {
}

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ZetaColors &&
runtimeType == other.runtimeType &&
brightness == other.brightness &&
contrast == other.contrast &&
primary == other.primary &&
secondary == other.secondary &&
error == other.error &&
cool == other.cool &&
warm == other.warm &&
white == other.white &&
black == other.black &&
surfacePrimary == other.surfacePrimary &&
surfaceSecondary == other.surfaceSecondary &&
surfaceTertiary == other.surfaceTertiary &&
blue == other.blue &&
green == other.green &&
red == other.red &&
orange == other.orange &&
purple == other.purple &&
yellow == other.yellow &&
teal == other.teal &&
pink == other.pink;

@override
int get hashCode =>
brightness.hashCode ^
contrast.hashCode ^
primary.hashCode ^
secondary.hashCode ^
error.hashCode ^
cool.hashCode ^
warm.hashCode ^
white.hashCode ^
black.hashCode ^
surfacePrimary.hashCode ^
surfaceSecondary.hashCode ^
surfaceTertiary.hashCode ^
blue.hashCode ^
green.hashCode ^
red.hashCode ^
orange.hashCode ^
purple.hashCode ^
yellow.hashCode ^
teal.hashCode ^
pink.hashCode;
List<Object?> get props => [
brightness,
contrast,
primary,
secondary,
error,
cool,
warm,
white,
black,
surfacePrimary,
surfaceSecondary,
surfaceTertiary,
];
}

enum _ZetaColorProperties {
Expand Down
File renamed without changes.
16 changes: 16 additions & 0 deletions lib/src/utils/equatable_dignosticable_mixin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';

/// A mixin that combines the functionality of `Diagnosticable` and `EquatableMixin`.
///
/// This mixin is useful for classes that need to be both equatable (i.e., support value comparison)
/// and support Flutter's diagnostic capabilities (e.g., for improved debugging output).
///
/// When using this mixin, ensure that the `toString` method conforms to the `Diagnosticable` signature,
/// which accepts an optional `minLevel` parameter.
mixin EquatableDiagnosticableMixin on EquatableMixin {
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return '${super.toString()}';
}
}
7 changes: 4 additions & 3 deletions lib/src/utils/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ extension ColorSwatches on ZetaWidgetStatus {
extension StringExtensions on String? {
/// Returns initials from a name.
String get initials {
if (this == null) return '';
if (this == null || (this?.isEmpty ?? true)) return '';
final List<String> nameParts = this!.split(RegExp(r'\W+'))..removeWhere((item) => item.isEmpty);
if (nameParts.isEmpty) return '';
return (nameParts.length > 1
Expand All @@ -104,9 +104,10 @@ extension StringExtensions on String? {
.toUpperCase();
}

/// Capitalizes fist letter of string.
/// Capitalizes first letter of string.
String capitalize() {
if (this == null) return '';
if (this == null || this!.isEmpty) return '';
if (this!.length == 1) return this!.toUpperCase();
return '${this![0].toUpperCase()}${this!.substring(1).toLowerCase()}';
}
}
2 changes: 1 addition & 1 deletion lib/zeta_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ export 'src/theme/tokens.dart';
export 'src/theme/typography.dart';
export 'src/utils/enums.dart';
export 'src/utils/extensions.dart';
export 'src/utils/utils.dart';
export 'src/utils/debounce.dart';
export 'src/zeta.dart';
5 changes: 5 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ environment:

dependencies:
collection: ^1.18.0
equatable: ^2.0.5
flutter:
sdk: flutter
flutter_slidable: ^3.1.0
Expand All @@ -30,6 +31,10 @@ dependencies:
web: ^0.5.1

dev_dependencies:
build_runner: ^2.4.10
flutter_test:
sdk: flutter
mockito: ^5.4.4
zds_analysis: ^1.0.0

flutter:
Expand Down
137 changes: 137 additions & 0 deletions test/src/theme/breakpoints_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:zeta_flutter/src/theme/breakpoints.dart';

import '../../test_utils/test_app.dart';

void main() {
group('BreakpointLocal extension', () {
test('returns DeviceType.mobilePortrait for widths <= 479', () {
const constraints = BoxConstraints(maxWidth: 479);
expect(constraints.deviceType, DeviceType.mobilePortrait);
});

test('returns DeviceType.mobileLandscape for widths <= 767', () {
const constraints = BoxConstraints(maxWidth: 767);
expect(constraints.deviceType, DeviceType.mobileLandscape);
});

test('returns DeviceType.tablet for widths <= 991', () {
const constraints = BoxConstraints(maxWidth: 991);
expect(constraints.deviceType, DeviceType.tablet);
});

test('returns DeviceType.desktop for widths <= 1279', () {
const constraints = BoxConstraints(maxWidth: 1279);
expect(constraints.deviceType, DeviceType.desktop);
});

test('returns DeviceType.desktopL for widths <= 1439', () {
const constraints = BoxConstraints(maxWidth: 1439);
expect(constraints.deviceType, DeviceType.desktopL);
});

test('returns DeviceType.desktopXL for widths > 1439', () {
const constraints = BoxConstraints(maxWidth: 1920);
expect(constraints.deviceType, DeviceType.desktopXL);
});
});

group('BreakpointFull extension', () {
testWidgets('returns DeviceType.mobilePortrait for widths <= 479', (WidgetTester tester) async {
await tester.pumpWidget(
TestApp(
home: MediaQuery(
data: const MediaQueryData(size: Size(479, 800)),
child: Builder(
builder: (context) {
expect(context.deviceType, DeviceType.mobilePortrait);
return Container();
},
),
),
),
);
});

testWidgets('returns DeviceType.mobileLandscape for widths <= 767', (WidgetTester tester) async {
await tester.pumpWidget(
TestApp(
home: MediaQuery(
data: const MediaQueryData(size: Size(767, 800)),
child: Builder(
builder: (context) {
expect(context.deviceType, DeviceType.mobileLandscape);
return Container();
},
),
),
),
);
});

testWidgets('returns DeviceType.tablet for widths <= 991', (WidgetTester tester) async {
await tester.pumpWidget(
TestApp(
home: MediaQuery(
data: const MediaQueryData(size: Size(991, 800)),
child: Builder(
builder: (context) {
expect(context.deviceType, DeviceType.tablet);
return Container();
},
),
),
),
);
});

testWidgets('returns DeviceType.desktop for widths <= 1279', (WidgetTester tester) async {
await tester.pumpWidget(
TestApp(
home: MediaQuery(
data: const MediaQueryData(size: Size(1279, 800)),
child: Builder(
builder: (context) {
expect(context.deviceType, DeviceType.desktop);
return Container();
},
),
),
),
);
});

testWidgets('returns DeviceType.desktopL for widths <= 1439', (WidgetTester tester) async {
await tester.pumpWidget(
TestApp(
home: MediaQuery(
data: const MediaQueryData(size: Size(1439, 800)),
child: Builder(
builder: (context) {
expect(context.deviceType, DeviceType.desktopL);
return Container();
},
),
),
),
);
});

testWidgets('returns DeviceType.desktopXL for widths > 1439', (WidgetTester tester) async {
await tester.pumpWidget(
TestApp(
home: MediaQuery(
data: const MediaQueryData(size: Size(1920, 800)),
child: Builder(
builder: (context) {
expect(context.deviceType, DeviceType.desktopXL);
return Container();
},
),
),
),
);
});
});
}
Loading

0 comments on commit 1d6b080

Please sign in to comment.