Skip to content

Commit

Permalink
Improve tests
Browse files Browse the repository at this point in the history
  • Loading branch information
simc committed Jul 22, 2019
1 parent d939702 commit 3405f33
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 80 deletions.
2 changes: 1 addition & 1 deletion hive/README.md
Expand Up @@ -105,7 +105,7 @@ The work on Hive has just started. If you want to contribute, it would be amazin
- [ ] Finalizing API
- [ ] Writing binary format spec
- [ ] Even more tests
- [ ] Benchmark and comparison
- [ ] Benchmarks and comparison

### Licence

Expand Down
13 changes: 12 additions & 1 deletion hive/lib/src/binary/frame.dart
Expand Up @@ -46,6 +46,8 @@ import 'package:hive/src/util/crc32.dart';
/// | uint8 value1 type
/// | List<uint8> value1 bytes
/// | ...
/// | uint8 valueN type
/// | List<uint8> valueN bytes
/// --------------------------
///
/// map
Expand All @@ -56,6 +58,10 @@ import 'package:hive/src/util/crc32.dart';
/// | uint8 value1 type
/// | List<uint8> value1 bytes
/// | ...
/// | uint8 keyN type
/// | List<uint8> keyN bytes
/// | uint8 valueN type
/// | List<uint8> valueN bytes
/// --------------------------
class Frame {
static const maxFrameLength = 1000 * 64;
Expand All @@ -65,7 +71,12 @@ class Frame {

final int length;

const Frame(this.key, this.value, [this.length]);
final bool overrideExisting;

const Frame(this.key, this.value, [this.length]) : overrideExisting = false;

const Frame.override(this.key, this.value, [this.length])
: overrideExisting = true;

bool get deleted => value == null;

Expand Down
47 changes: 21 additions & 26 deletions hive/lib/src/box/box_impl.dart
Expand Up @@ -6,6 +6,7 @@ import 'package:hive/src/backend/storage_backend.dart';
import 'package:hive/src/binary/frame.dart';
import 'package:hive/src/box/box_base.dart';
import 'package:hive/src/box/box_options.dart';
import 'package:hive/src/box/change_notifier.dart';
import 'package:hive/src/hive_impl.dart';
import 'package:meta/meta.dart';

Expand Down Expand Up @@ -35,23 +36,27 @@ class BoxImpl extends BoxBase {
static const deletedRatio = 0.15;
static const deletedThreshold = 40;

final HiveImpl hive;
@override
final String name;
final HiveImpl hive;
final BoxOptions options;
final StorageBackend _backend;
final _streamController = StreamController<BoxEvent>.broadcast();

final ChangeNotifier _notifier;
Map<String, BoxEntry> _entries = HashMap();

bool _open = true;
int _deletedEntries = 0;

BoxImpl(this.hive, this.name, this.options, this._backend) : super(hive);
BoxImpl(this.hive, this.name, this.options, this._backend)
: _notifier = ChangeNotifier(),
super(hive);

@visibleForTesting
BoxImpl.debug(
this.hive, this.name, this.options, this._backend, this._entries)
: super(hive);
this.hive, this.name, this.options, this._backend, this._entries,
[ChangeNotifier notifier])
: _notifier = notifier ?? ChangeNotifier(),
super(hive);

@override
bool get isOpen => _open;
Expand All @@ -75,15 +80,7 @@ class BoxImpl extends BoxBase {
@override
Stream<BoxEvent> watch({String key}) {
checkOpen();
if (key != null) {
return _streamController.stream.where((it) => it.key == key);
} else {
return _streamController.stream;
}
}

void _notifyChange(String key, dynamic value) {
_streamController.add(BoxEvent(key, value));
return _notifier.watch(key: key);
}

Future initialize() async {
Expand Down Expand Up @@ -136,7 +133,7 @@ class BoxImpl extends BoxBase {

await performCompactationIfNeeded();

_notifyChange(key, value);
_notifier.notify(key, value);
}

@override
Expand Down Expand Up @@ -180,8 +177,8 @@ class BoxImpl extends BoxBase {

await performCompactationIfNeeded();

if (_streamController.hasListener) {
kvPairs.forEach(_notifyChange);
for (var frame in frames) {
_notifier.notify(frame.key, frame.value);
}
}

Expand Down Expand Up @@ -215,7 +212,7 @@ class BoxImpl extends BoxBase {
_deletedEntries = 0;

for (var key in oldEntries.keys) {
_notifyChange(key, null);
_notifier.notify(key, null);
}

return oldEntries.length;
Expand All @@ -225,11 +222,8 @@ class BoxImpl extends BoxBase {
Future<void> compact() async {
checkOpen();
if (_deletedEntries == 0) return;
var newEntries = await _backend.compact(_entries);
if (newEntries != null) {
_entries = newEntries;
_deletedEntries = 0;
}
_entries = await _backend.compact(_entries);
_deletedEntries = 0;
}

@visibleForTesting
Expand All @@ -248,7 +242,7 @@ class BoxImpl extends BoxBase {
if (!_open) return;

await waitForRunningTransactions();
await _streamController.close();
await _notifier.close();

_open = false;
hive.unregisterBox(name);
Expand All @@ -257,8 +251,9 @@ class BoxImpl extends BoxBase {

@override
Future<void> deleteFromDisk() async {
await _streamController.close();
await waitForRunningTransactions();
await _notifier.close();

_open = false;
hive.unregisterBox(name);
await _backend.deleteFromDisk();
Expand Down
29 changes: 29 additions & 0 deletions hive/lib/src/box/change_notifier.dart
@@ -0,0 +1,29 @@
import 'dart:async';

import 'package:hive/hive.dart';
import 'package:meta/meta.dart';

class ChangeNotifier {
final StreamController<BoxEvent> _streamController;

ChangeNotifier() : _streamController = StreamController<BoxEvent>.broadcast();

@visibleForTesting
ChangeNotifier.debug(this._streamController);

void notify(String key, dynamic value) {
_streamController.add(BoxEvent(key, value));
}

Stream<BoxEvent> watch({String key}) {
if (key != null) {
return _streamController.stream.where((it) => it.key == key);
} else {
return _streamController.stream;
}
}

Future close() {
return _streamController.close();
}
}
2 changes: 1 addition & 1 deletion hive/lib/src/box/transaction_box.dart
Expand Up @@ -36,7 +36,7 @@ class TransactionBox extends BoxBase {

@override
Stream<BoxEvent> watch() {
throw UnsupportedError('Watching is not supported within a transaction.');
throw UnsupportedError('Watching a transaction is not supported.');
}

@override
Expand Down
33 changes: 32 additions & 1 deletion hive/test/box_base_test.dart
@@ -1 +1,32 @@
void main() {}
import 'package:hive/hive.dart';
import 'package:hive/src/box/box_base.dart';
import 'package:mockito/mockito.dart';
import 'package:pedantic/pedantic.dart';
import 'package:test/test.dart';

class BoxBaseMock extends BoxBase with Mock {
BoxBaseMock(TypeRegistry parent) : super(parent);
}

void main() {
group('BoxBase', () {
test('.transaction() & .waitForRunningTransactions()', () async {
var boxMock = BoxBaseMock(null);

var finished = false;
unawaited(
boxMock.transaction((trx) async {
await Future.delayed(Duration(milliseconds: 100));
await trx.put('key', 'val');
}).then((_) {
finished = true;
}),
);
expect(finished, false);
await boxMock.waitForRunningTransactions();
expect(finished, true);

verify(boxMock.putAll({'key': 'val'}));
});
});
}

0 comments on commit 3405f33

Please sign in to comment.