54 lines
2.7 KiB
TypeScript
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');
|
|
});
|
|
});
|