Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@TestOn('vm')
library;

import 'package:test/test.dart';
import 'package:yet_another_json_isolate/yet_another_json_isolate.dart';

void main() {
group('io implementation', () {
test('throws when initialize is called twice', () async {
final isolate = YAJsonIsolate();
await isolate.initialize();
addTearDown(isolate.dispose);
expect(isolate.initialize(), throwsA(isA<AssertionError>()));
});

test('exposes the provided debug name', () {
final isolate = YAJsonIsolate(debugName: 'my-isolate');
expect(isolate.debugName, 'my-isolate');
});
});
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:convert';

import 'package:test/test.dart';
import 'package:yet_another_json_isolate/yet_another_json_isolate.dart';

Expand All @@ -6,7 +8,8 @@ const _jsonMap = {'a': 1, 'b': 2};

void main() {
late YAJsonIsolate isolate;
group('Initialize isolate manually', () {

group('with manual initialize', () {
setUp(() async {
isolate = YAJsonIsolate();
await isolate.initialize();
Expand All @@ -16,18 +19,16 @@ void main() {
await isolate.dispose();
});

test('decode', () async {
final json = await isolate.decode(_jsonString);
expect(json, _jsonMap);
test('decodes a JSON object', () async {
expect(await isolate.decode(_jsonString), _jsonMap);
});

test('encode', () async {
final encoded = await isolate.encode(_jsonMap);
expect(encoded, _jsonString);
test('encodes a JSON object', () async {
expect(await isolate.encode(_jsonMap), _jsonString);
});
});

group('Do not initialize isolate manually ', () {
group('without manual initialize', () {
setUp(() {
isolate = YAJsonIsolate();
});
Expand All @@ -36,14 +37,178 @@ void main() {
await isolate.dispose();
});

test('decode', () async {
final json = await isolate.decode(_jsonString);
expect(json, _jsonMap);
test('decodes lazily on first call', () async {
expect(await isolate.decode(_jsonString), _jsonMap);
});

test('encode', () async {
test('encodes lazily on first call', () async {
expect(await isolate.encode(_jsonMap), _jsonString);
});
});

group('data types', () {
setUp(() {
isolate = YAJsonIsolate();
});

tearDown(() async {
await isolate.dispose();
});

test('decodes a top level list', () async {
expect(await isolate.decode('[1,2,3]'), [1, 2, 3]);
});

test('encodes a top level list', () async {
expect(await isolate.encode([1, 2, 3]), '[1,2,3]');
});

test('handles nested structures', () async {
const nested = {
'list': [
1,
{'nested': true},
],
'map': {'inner': null},
};
final encoded = await isolate.encode(nested);
expect(await isolate.decode(encoded), nested);
});

test('handles ints, doubles, booleans, null and strings', () async {
const value = {
'int': 1,
'double': 1.5,
'boolTrue': true,
'boolFalse': false,
'null': null,
'string': 'hello',
};
final encoded = await isolate.encode(value);
expect(await isolate.decode(encoded), value);
});

test('preserves unicode characters', () async {
const value = {'emoji': '🚀', 'text': 'Grüße'};
final encoded = await isolate.encode(value);
expect(await isolate.decode(encoded), value);
});

test('decodes a bare JSON primitive', () async {
expect(await isolate.decode('42'), 42);
expect(await isolate.decode('"text"'), 'text');
expect(await isolate.decode('null'), isNull);
});

test('round trips an encoded value back to the original', () async {
final encoded = await isolate.encode(_jsonMap);
expect(encoded, _jsonString);
expect(await isolate.decode(encoded), _jsonMap);
});
});

group('error handling', () {
setUp(() {
isolate = YAJsonIsolate();
});

tearDown(() async {
await isolate.dispose();
});

test('throws FormatException for invalid JSON', () async {
await expectLater(
isolate.decode('{not valid json'),
throwsFormatException,
);
});

test('throws for a non encodable object', () async {
await expectLater(
isolate.encode(DateTime.now()),
throwsA(isA<JsonUnsupportedObjectError>()),
);
});

test('stays usable after a decode error', () async {
await expectLater(isolate.decode('{bad'), throwsFormatException);
expect(await isolate.decode(_jsonString), _jsonMap);
});

test('stays usable after an encode error', () async {
await expectLater(
isolate.encode(DateTime.now()),
throwsA(isA<JsonUnsupportedObjectError>()),
);
expect(await isolate.encode(_jsonMap), _jsonString);
});
});

group('concurrency and ordering', () {
setUp(() async {
isolate = YAJsonIsolate();
await isolate.initialize();
});

tearDown(() async {
await isolate.dispose();
});

test('resolves concurrent decodes to the correct results', () async {
final results = await Future.wait([
isolate.decode('1'),
isolate.decode('2'),
isolate.decode('3'),
isolate.decode('[4]'),
]);
expect(results, [
1,
2,
3,
[4],
]);
});

test('resolves interleaved encodes and decodes', () async {
final results = await Future.wait([
isolate.encode({'a': 1}),
isolate.decode('[1,2]'),
isolate.encode([true, false]),
]);
expect(results, [
'{"a":1}',
[1, 2],
'[true,false]',
]);
});

test('handles many sequential operations', () async {
for (var i = 0; i < 50; i++) {
expect(await isolate.decode('$i'), i);
}
});
});

group('lifecycle', () {
test('dispose can be awaited on a lazily initialized isolate', () async {
final lazyIsolate = YAJsonIsolate();
await lazyIsolate.decode(_jsonString);
await expectLater(lazyIsolate.dispose(), completes);
});

test('two isolates operate independently', () async {
final first = YAJsonIsolate();
final second = YAJsonIsolate();
addTearDown(first.dispose);
addTearDown(second.dispose);

final results = await Future.wait([
first.decode('[1]'),
second.decode('[2]'),
]);
expect(results, [
[1],
[2],
]);
});
});
}
Loading