Skip to content
Open
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
29 changes: 29 additions & 0 deletions .github/workflows/validate-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,35 @@ on:
- 'example/*.tsx'

jobs:
test:
name: Test JS (jest)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Restore node_modules from cache
uses: actions/cache@v4
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-

- name: Install node_modules
run: yarn install --frozen-lockfile

- name: Run Jest
run: yarn test

compile:
name: Compile JS (tsc)
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: ['module:@react-native/babel-preset'],
}
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"@expo/config-plugins": "^7.8.4",
"@jamesacarr/eslint-formatter-github-actions": "^0.2.0",
"@react-native-community/eslint-config": "^3.0.2",
"@react-native/babel-preset": "0.73.20",
"@release-it/conventional-changelog": "^8.0.1",
"@types/jest": "^29.5.11",
"@types/react": "~18.2.48",
Expand Down Expand Up @@ -99,6 +100,10 @@
"modulePathIgnorePatterns": [
"<rootDir>/example/node_modules",
"<rootDir>/lib/"
],
"testPathIgnorePatterns": [
"/node_modules/",
"<rootDir>/example/"
]
},
"release-it": {
Expand Down Expand Up @@ -126,11 +131,6 @@
"trailingComma": "es5",
"useTabs": false
},
"babel": {
"presets": [
"module:metro-react-native-babel-preset"
]
},
"react-native-builder-bob": {
"source": "src",
"output": "lib",
Expand Down
1 change: 0 additions & 1 deletion src/__tests__/index.test.tsx

This file was deleted.

135 changes: 135 additions & 0 deletions src/__tests__/withAndroidGpuLibraries.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import type {
AndroidConfig,
ExportedConfig,
ModProps,
} from '@expo/config-plugins'
import { withAndroidGpuLibraries } from '../expo-plugin/withAndroidGpuLibraries'

type AndroidManifest = AndroidConfig.Manifest.AndroidManifest
type ManifestUsesLibrary = AndroidConfig.Manifest.ManifestUsesLibrary
type ManifestApplicationWithNativeLibraries =
AndroidConfig.Manifest.ManifestApplication & {
'uses-native-library'?: ManifestUsesLibrary[]
}

function createExpoConfig(): ExportedConfig {
return { name: 'TfliteExample', slug: 'tflite-example' }
}

function createManifest(
usesNativeLibrary?: ManifestUsesLibrary[]
): AndroidManifest {
const application: ManifestApplicationWithNativeLibraries = {
$: { 'android:name': '.MainApplication' },
}
if (usesNativeLibrary != null)
application['uses-native-library'] = usesNativeLibrary

return {
manifest: {
$: { 'xmlns:android': 'http://schemas.android.com/apk/res/android' },
queries: [],
application: [application],
},
}
}

/**
* Runs the `withAndroidGpuLibraries` plugin's `android.manifest` mod against the
* given manifest, the same way `expo prebuild` would, and returns the result.
*/
async function applyPlugin(
manifest: AndroidManifest,
enabledLibraries: boolean | string[]
): Promise<AndroidManifest> {
const expoConfig = createExpoConfig()
const config = withAndroidGpuLibraries(
expoConfig,
enabledLibraries
) as ExportedConfig
const mod = config.mods?.android?.manifest
if (mod == null)
throw new Error('withAndroidGpuLibraries did not register a manifest mod!')

const modRequest: ModProps<AndroidManifest> = {
projectRoot: '/app',
platformProjectRoot: '/app/android',
modName: 'manifest',
platform: 'android',
introspect: false,
}
const result = await mod({
...config,
modResults: manifest,
modRequest: modRequest,
modRawConfig: expoConfig,
})

return result.modResults
}

function getUsesNativeLibraries(
manifest: AndroidManifest
): ManifestUsesLibrary[] {
const application: ManifestApplicationWithNativeLibraries | undefined =
manifest.manifest.application?.[0]
if (application == null) throw new Error('No <application> in the manifest!')
return application['uses-native-library'] ?? []
}

function getUsesNativeLibraryNames(manifest: AndroidManifest): string[] {
return getUsesNativeLibraries(manifest).map((lib) => lib.$['android:name'])
}

describe('withAndroidGpuLibraries', () => {
it('adds libOpenCL.so when enabled with `true`', async () => {
const manifest = await applyPlugin(createManifest(), true)

expect(getUsesNativeLibraryNames(manifest)).toEqual(['libOpenCL.so'])
})

it('marks the added libraries as not required', async () => {
const manifest = await applyPlugin(createManifest(), true)

expect(getUsesNativeLibraries(manifest)[0]?.$).toEqual({
'android:name': 'libOpenCL.so',
'android:required': false,
})
})

it('adds libOpenCL.so alongside the explicitly listed libraries', async () => {
const manifest = await applyPlugin(createManifest(), [
'libOpenCL-pixel.so',
'libGLES_mali.so',
])

expect(getUsesNativeLibraryNames(manifest)).toEqual([
'libOpenCL.so',
'libOpenCL-pixel.so',
'libGLES_mali.so',
])
})

it('does not duplicate entries when prebuild runs twice', async () => {
const libraries = ['libOpenCL-pixel.so']
const once = await applyPlugin(createManifest(), libraries)
const twice = await applyPlugin(once, libraries)

expect(getUsesNativeLibraryNames(twice)).toEqual([
'libOpenCL.so',
'libOpenCL-pixel.so',
])
})

it('keeps unrelated <uses-native-library> entries that are already present', async () => {
const existing: ManifestUsesLibrary = {
$: { 'android:name': 'libsomething-else.so', 'android:required': 'true' },
}
const manifest = await applyPlugin(createManifest([existing]), true)

expect(getUsesNativeLibraryNames(manifest)).toEqual([
'libsomething-else.so',
'libOpenCL.so',
])
})
})
Loading