alt/apps/client/test/contracts/alt_api_result_test.dart
toki 259a86c2fa chore: archive completed task files and add contract-related files
- Move 01_contract_mapping files to archive
- Add alt_api_result.dart contract implementation
- Add alt_api_result_test.dart
2026-06-02 10:15:26 +09:00

138 lines
4.6 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:alt_client/src/contracts/alt_api_result.dart';
import 'package:alt_client/src/generated/alt/v1/backtest.pb.dart';
import 'package:alt_client/src/generated/alt/v1/common.pb.dart';
import 'package:alt_client/src/generated/alt/v1/market.pb.dart';
void main() {
group('AltApiError mapping', () {
test('fromErrorInfo preserves stable code and message', () {
final info = ErrorInfo(code: 'NOT_FOUND', message: 'instrument missing');
final error = AltApiError.fromErrorInfo(info);
expect(error.code, equals('NOT_FOUND'));
expect(error.message, equals('instrument missing'));
});
test('keeps empty fields when ErrorInfo is empty', () {
final error = AltApiError.fromErrorInfo(ErrorInfo());
expect(error.code, isEmpty);
expect(error.message, isEmpty);
});
test('value equality is based on code and message', () {
final a = AltApiError.fromErrorInfo(
ErrorInfo(code: 'E1', message: 'm'),
);
final b = const AltApiError(code: 'E1', message: 'm');
expect(a, equals(b));
expect(a.hashCode, equals(b.hashCode));
});
});
group('AltApiResult variants', () {
test('success carries the decoded value', () {
const result = AltApiResult<int>.success(42);
expect(result, isA<AltApiSuccess<int>>());
expect((result as AltApiSuccess<int>).value, equals(42));
});
test('apiError carries the mapped error', () {
final error = AltApiError.fromErrorInfo(
ErrorInfo(code: 'BAD', message: 'rejected'),
);
final result = AltApiResult<int>.apiError(error);
expect(result, isA<AltApiFailure<int>>());
expect((result as AltApiFailure<int>).error, equals(error));
});
test('transportFailure stays a stable state without ErrorInfo', () {
const result = AltApiResult<int>.transportFailure(
AltTransportKind.timeout,
detail: 'no response within 5s',
);
expect(result, isA<AltTransportFailure<int>>());
final failure = result as AltTransportFailure<int>;
expect(failure.kind, equals(AltTransportKind.timeout));
expect(failure.detail, equals('no response within 5s'));
});
test('transportFailure supports a bare kind with no detail', () {
const result =
AltApiResult<int>.transportFailure(AltTransportKind.disconnected);
final failure = result as AltTransportFailure<int>;
expect(failure.kind, equals(AltTransportKind.disconnected));
expect(failure.detail, isNull);
});
test('exhaustive switch covers every variant', () {
String describe(AltApiResult<int> result) {
return switch (result) {
AltApiSuccess<int>() => 'success',
AltApiFailure<int>() => 'apiError',
AltTransportFailure<int>() => 'transport',
};
}
expect(describe(const AltApiResult<int>.success(1)), equals('success'));
expect(
describe(
const AltApiResult<int>.apiError(
AltApiError(code: 'E', message: 'm'),
),
),
equals('apiError'),
);
expect(
describe(
const AltApiResult<int>.transportFailure(AltTransportKind.unknown),
),
equals('transport'),
);
});
});
group('altResponseError extraction', () {
test('reads typed error from each supported response', () {
final error = ErrorInfo(code: 'X', message: 'boom');
final responses = <Object>[
ListInstrumentsResponse(error: error),
ListBarsResponse(error: error),
StartBacktestResponse(error: error),
GetBacktestRunResponse(error: error),
GetBacktestResultResponse(error: error),
ListBacktestRunsResponse(error: error),
GetBacktestRunDetailResponse(error: error),
CompareBacktestRunsResponse(error: error),
];
for (final response in responses) {
final extracted = altResponseError(response);
expect(extracted, isNotNull, reason: '${response.runtimeType}');
expect(extracted!.code, equals('X'));
expect(extracted.message, equals('boom'));
}
});
test('returns null when a supported response has no error set', () {
expect(altResponseError(ListInstrumentsResponse()), isNull);
expect(altResponseError(ListBarsResponse()), isNull);
expect(altResponseError(GetBacktestRunDetailResponse()), isNull);
});
test('returns null for unsupported response types', () {
expect(altResponseError(HelloResponse()), isNull);
expect(altResponseError(ListInstrumentsRequest()), isNull);
expect(altResponseError('not a message'), isNull);
});
});
}