d3ro-voice/apps/mobile-rn/__tests__/recording-native-contract.test.ts
2026-08-29 18:33:45 +09:00

54 lines
2.7 KiB
TypeScript

import fs from 'node:fs';
import path from 'node:path';
const root = path.resolve(__dirname, '..');
const android = path.join(root, 'android', 'app', 'src', 'main');
function read(relativePath: string): string {
return fs.readFileSync(path.join(android, relativePath), 'utf8');
}
describe('Android foreground recording contract', () => {
test('declares the microphone foreground service and required permissions', () => {
const manifest = read('AndroidManifest.xml');
expect(manifest).toContain('android.permission.FOREGROUND_SERVICE_MICROPHONE');
expect(manifest).toContain('android.permission.WAKE_LOCK');
expect(manifest).toContain('android:name=".D3RORecordingService"');
expect(manifest).toContain('android:foregroundServiceType="microphone"');
expect(manifest).toContain('android:stopWithTask="false"');
});
test('checkpoints a WAV, handles audio focus and never restarts capture invisibly', () => {
const service = read(path.join('java', 'com', 'd3ro', 'voice', 'D3RORecordingService.kt'));
const journal = read(path.join('java', 'com', 'd3ro', 'voice', 'D3RORecordingJournal.kt'));
expect(service).toContain('ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE');
expect(service).toContain('AUDIOFOCUS_LOSS_TRANSIENT');
expect(service).toContain('isClientSilenced');
expect(service).toContain('START_NOT_STICKY');
expect(service).toContain('MIN_CONTINUE_FREE_BYTES');
expect(journal).toContain('fun recoverAbandoned');
expect(journal).toContain('writeWavHeader');
expect(journal).toContain('process-restarted');
});
test('FileProvider exposes only staged cache files with read-only URI grants', () => {
const manifest = read('AndroidManifest.xml');
const paths = read(path.join('res', 'xml', 'd3ro_file_paths.xml'));
const module = read(path.join('java', 'com', 'd3ro', 'voice', 'D3ROFileShareModule.kt'));
const portableFile = fs.readFileSync(
path.join(root, 'src', 'features', 'data-portability', 'portable-file.ts'),
'utf8',
);
expect(manifest).toContain('android:exported="false"');
expect(paths).toContain('path="shared_exports/"');
expect(paths).not.toContain('path="portable_exports/"');
expect(paths).not.toContain('path="."');
expect(module).toContain('PORTABLE_EXPORT_DIRECTORY = "portable_exports"');
expect(module).toContain('candidate.parentFile == sourceDirectory');
expect(portableFile).toContain("PORTABLE_EXPORT_DIRECTORY = 'portable_exports'");
expect(portableFile).toContain('await FileSystem.mkdir(directory)');
expect(module).toContain('Intent.FLAG_GRANT_READ_URI_PERMISSION');
expect(module).not.toContain('FLAG_GRANT_WRITE_URI_PERMISSION');
expect(module).toContain('revokeUriPermission');
});
});