You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
8.7 KiB
316 lines
8.7 KiB
// ignore_for_file: discarded_futures |
|
|
|
import 'dart:async'; |
|
|
|
import 'package:flutter/foundation.dart'; |
|
import 'package:mocktail/mocktail.dart'; |
|
import 'package:neon/src/settings/models/select_option.dart'; |
|
import 'package:neon/src/settings/models/storage.dart'; |
|
import 'package:neon/src/settings/models/toggle_option.dart'; |
|
import 'package:test/test.dart'; |
|
|
|
class MockStorage extends Mock implements SettingsStorage {} |
|
|
|
class MockCallbackFunction extends Mock { |
|
FutureOr<void> call(); |
|
} |
|
|
|
enum StorageKey implements Storable { |
|
key._('storage-key'); |
|
|
|
const StorageKey._(this.value); |
|
|
|
@override |
|
final String value; |
|
} |
|
|
|
enum SelectValues { |
|
first, |
|
second, |
|
third, |
|
} |
|
|
|
void main() { |
|
final storage = MockStorage(); |
|
const key = StorageKey.key; |
|
String labelBuilder(final _) => 'label'; |
|
|
|
group('SelectOption', () { |
|
final valuesLabel = { |
|
SelectValues.first: (final _) => 'first', |
|
SelectValues.second: (final _) => 'second', |
|
SelectValues.third: (final _) => 'third', |
|
}; |
|
|
|
late SelectOption<SelectValues> option; |
|
|
|
setUp(() { |
|
when(() => storage.setString(key.value, any())).thenAnswer((final _) async {}); |
|
when(() => storage.remove(key.value)).thenAnswer((final _) async => true); |
|
|
|
option = SelectOption<SelectValues>( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: SelectValues.first, |
|
values: valuesLabel, |
|
); |
|
}); |
|
|
|
tearDown(() { |
|
reset(storage); |
|
option.dispose(); |
|
}); |
|
|
|
test('Create', () { |
|
expect(option.value, option.defaultValue, reason: 'Should default to defaultValue.'); |
|
|
|
when(() => storage.getString(key.value)).thenReturn('SelectValues.second'); |
|
|
|
option = SelectOption<SelectValues>( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: SelectValues.first, |
|
values: valuesLabel, |
|
); |
|
|
|
expect(option.value, SelectValues.second, reason: 'Should load value from storage when available.'); |
|
}); |
|
|
|
test('Depend', () { |
|
final enabled = ValueNotifier(false); |
|
final callback = MockCallbackFunction(); |
|
|
|
option = SelectOption<SelectValues>.depend( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: SelectValues.first, |
|
values: valuesLabel, |
|
enabled: enabled, |
|
)..addListener(callback.call); |
|
|
|
expect(option.enabled, enabled.value, reason: 'Should initialize with enabled value.'); |
|
|
|
enabled.value = true; |
|
verify(callback.call).called(1); |
|
expect(option.enabled, enabled.value, reason: 'Should update the enabled state.'); |
|
}); |
|
|
|
test('Update', () { |
|
final callback = MockCallbackFunction(); |
|
option |
|
..addListener(callback.call) |
|
..value = SelectValues.third; |
|
|
|
verify(callback.call).called(1); |
|
verify(() => storage.setString(key.value, 'SelectValues.third')).called(1); |
|
expect(option.value, SelectValues.third, reason: 'Should update the value.'); |
|
|
|
option.value = SelectValues.third; |
|
verifyNever(callback.call); // Don't notify with the same value |
|
expect(option.value, SelectValues.third, reason: 'Should keep the value.'); |
|
}); |
|
|
|
test('Disable', () { |
|
final callback = MockCallbackFunction(); |
|
option.addListener(callback.call); |
|
|
|
expect(option.enabled, true, reason: 'Should default to enabled'); |
|
|
|
option.enabled = false; |
|
verify(callback.call).called(1); |
|
expect(option.enabled, false, reason: 'Should disable option.'); |
|
|
|
option.enabled = false; |
|
verifyNever(callback.call); // Don't notify with the same value |
|
expect(option.enabled, false, reason: 'Should keep the value.'); |
|
}); |
|
|
|
test('Change values', () { |
|
final callback = MockCallbackFunction(); |
|
option.addListener(callback.call); |
|
|
|
expect(option.values, equals(valuesLabel)); |
|
|
|
final newValues = { |
|
SelectValues.second: (final _) => 'second', |
|
SelectValues.third: (final _) => 'third', |
|
}; |
|
|
|
option.values = newValues; |
|
verify(callback.call).called(1); |
|
expect(option.values, equals(newValues), reason: 'Should change values.'); |
|
|
|
option.values = newValues; |
|
verifyNever(callback.call); // Don't notify with the same value |
|
expect(option.values, newValues, reason: 'Should keep the values.'); |
|
}); |
|
|
|
test('Reset', () { |
|
final callback = MockCallbackFunction(); |
|
option |
|
..value = SelectValues.third |
|
..addListener(callback.call); |
|
|
|
expect(option.value, SelectValues.third); |
|
|
|
option.reset(); |
|
|
|
verify(callback.call).called(1); |
|
verify(() => storage.remove(key.value)).called(1); |
|
expect(option.value, option.defaultValue, reason: 'Should reset the value.'); |
|
}); |
|
|
|
test('Serialize null', () { |
|
final option = SelectOption<SelectValues?>( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: null, |
|
values: valuesLabel, |
|
); |
|
|
|
expect(option.serialize(), null, reason: 'Should serialize to null. A string containing "null" is an error'); |
|
}); |
|
|
|
test('Deserialize', () { |
|
final option = SelectOption<SelectValues?>( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: null, |
|
values: valuesLabel, |
|
); |
|
|
|
// ignore: cascade_invocations |
|
option.load('SelectValues.second'); |
|
|
|
expect(option.value, SelectValues.second); |
|
}); |
|
|
|
test('Stream', () async { |
|
final option = SelectOption<SelectValues?>( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: null, |
|
values: valuesLabel, |
|
); |
|
|
|
expect(await option.stream.first, option.defaultValue); |
|
option.value = SelectValues.second; |
|
expect(await option.stream.first, SelectValues.second); |
|
}); |
|
}); |
|
|
|
group('ToggleOption', () { |
|
late ToggleOption option; |
|
|
|
setUp(() { |
|
when(() => storage.setBool(key.value, any())).thenAnswer((final _) async {}); |
|
when(() => storage.remove(key.value)).thenAnswer((final _) async => true); |
|
|
|
option = ToggleOption( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: true, |
|
); |
|
}); |
|
|
|
tearDown(() { |
|
reset(storage); |
|
option.dispose(); |
|
}); |
|
|
|
test('Create', () { |
|
expect(option.value, option.defaultValue, reason: 'Should default to defaultValue.'); |
|
|
|
when(() => storage.getBool(key.value)).thenReturn(true); |
|
|
|
option = ToggleOption( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: false, |
|
); |
|
|
|
expect(option.value, true, reason: 'Should load value from storage when available.'); |
|
}); |
|
|
|
test('Depend', () { |
|
final enabled = ValueNotifier(false); |
|
final callback = MockCallbackFunction(); |
|
|
|
option = ToggleOption.depend( |
|
storage: storage, |
|
key: key, |
|
label: labelBuilder, |
|
defaultValue: true, |
|
enabled: enabled, |
|
)..addListener(callback.call); |
|
|
|
expect(option.enabled, enabled.value, reason: 'Should initialize with enabled value.'); |
|
|
|
enabled.value = true; |
|
verify(callback.call).called(1); |
|
expect(option.enabled, enabled.value, reason: 'Should update the enabled state.'); |
|
}); |
|
|
|
test('Update', () { |
|
final callback = MockCallbackFunction(); |
|
option |
|
..addListener(callback.call) |
|
..value = false; |
|
|
|
verify(callback.call).called(1); |
|
verify(() => storage.setBool(key.value, false)).called(1); |
|
expect(option.value, false, reason: 'Should update the value.'); |
|
|
|
option.value = false; |
|
verifyNever(callback.call); // Don't notify with the same value |
|
expect(option.value, false, reason: 'Should keep the value.'); |
|
}); |
|
|
|
test('Disable', () { |
|
final callback = MockCallbackFunction(); |
|
option.addListener(callback.call); |
|
|
|
expect(option.enabled, true, reason: 'Should default to enabled'); |
|
|
|
option.enabled = false; |
|
verify(callback.call).called(1); |
|
expect(option.enabled, false, reason: 'Should disable option.'); |
|
|
|
option.enabled = false; |
|
verifyNever(callback.call); // Don't notify with the same value |
|
expect(option.enabled, false, reason: 'Should keep the value.'); |
|
}); |
|
|
|
test('Reset', () { |
|
final callback = MockCallbackFunction(); |
|
option |
|
..value = false |
|
..addListener(callback.call); |
|
|
|
expect(option.value, false); |
|
|
|
option.reset(); |
|
|
|
verify(callback.call).called(1); |
|
verify(() => storage.remove(key.value)).called(1); |
|
expect(option.value, option.defaultValue, reason: 'Should reset the value.'); |
|
}); |
|
|
|
test('Deserialize', () { |
|
expect(option.value, true); |
|
|
|
// ignore: cascade_invocations |
|
option.load(false); |
|
|
|
expect(option.value, false); |
|
}); |
|
}); |
|
}
|
|
|