Skip to content

Commit

Permalink
tests: add + support runtime tests
Browse files Browse the repository at this point in the history
  • Loading branch information
larpon committed Sep 19, 2024
1 parent cc06c7b commit 2a5d023
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 2 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ here](https://github.com/vlang/vab/blob/3091ade4c9792c6a37596ccfa9299fb269d3160e
In either case the following dependencies is required before `vab` will work
as intented.

Dependencies:
## Runtime dependencies
* V
* Java (JDK) >= 8 (>= 9 on Windows)
* Android SDK
Expand Down Expand Up @@ -127,7 +127,8 @@ EMULATOR # Absolute path to the emulator to use
```

```bash
VAB_FLAGS # Use to pass flags to vab. Command-line flags overwrites any flags/values set via VAB_FLAGS.
VAB_EXE # Absolute path to a vab executable (Used in tests and sub-cmd execution)
VAB_FLAGS # Used to pass flags to vab. Command-line flags overwrites any flags/values set via VAB_FLAGS.
VAB_KILL_ADB # Set to let vab kill adb after use. This is useful on some hosts.
```

Expand Down Expand Up @@ -203,6 +204,12 @@ The accompaning script used in the video can be found here:
See [*"Where is the `examples` folder?"*](docs/FAQ.md#where-is-the-examples-folder)
in the [FAQ](docs/FAQ.md).

# Tests

`vab`, like many other V modules, can be tested with `v test .`.
Note that `vab` has *runtime* tests that requires all [runtime dependencies](#runtime-dependencies)
to be installed in order for the tests to run correctly.

# Notes

`vab` targets as low an API level as possible by default for maximum
Expand Down
1 change: 1 addition & 0 deletions cli/cli.v
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub const vab_env_vars = [
'AAPT2',
'JAVA_HOME',
'VEXE',
'VAB_EXE',
'VMODULES',
]

Expand Down
85 changes: 85 additions & 0 deletions tests/at-runtime/vab_build_apk_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import os
import vab.vabxt
import vab.vxt
import vab.android.util

const test_dir_base = os.join_path(os.vtmp_dir(), 'vab', 'tests', 'runtime')
const apk_arch_dirs = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64', 'armeabi']

fn setup_apk_build(id string) (string, string) {
test_dir := os.join_path(test_dir_base, id)
os.rm(test_dir) or {}
os.mkdir_all(test_dir) or { panic('mkdir_all failed making "${test_dir}": ${err}') }

// vab (per design) implicitly deploys to any devices sat via `--device-id`.
// Make sure no deployment is done after build if CI/other sets `ANDROID_SERIAL`
os.unsetenv('ANDROID_SERIAL')
vab := vabxt.vabexe()
assert vab != '', 'vab needs to be installed to run this test'
return vab, test_dir
}

fn v_example(path string) string {
v_root := vxt.home()
examples_root := os.join_path(v_root, 'examples')
example := os.join_path(examples_root, ...path.split('/'))
assert os.is_file(example) || os.is_dir(example) == true, 'example not found. Ensure a full V source install (with examples) is present'
return example
}

fn run(cmd string) {
eprintln('running: ${cmd}')
res := os.execute(cmd)
if res.exit_code != 0 {
dump(res.output)
}
assert res.exit_code == 0
}

fn extract_and_check_apk(libname string, path string) {
expected_lib_name := libname
expected_apk := os.join_path(path, '${expected_lib_name}.apk')
assert os.is_file(expected_apk)

extract_dir := os.join_path(path, 'extracted')
extracted_apk_path := os.join_path(extract_dir, expected_lib_name)
util.unzip(expected_apk, extracted_apk_path) or {
panic('unzip failed extracting "${expected_apk}": ${err}')
}

dump(os.ls(extracted_apk_path) or { panic('ls failed on "${extracted_apk_path}": ${err}') })
// test that expected libs are actually present in the apk
for arch in apk_arch_dirs {
lib_dir := os.join_path(extracted_apk_path, 'lib', arch)
dump(os.ls(lib_dir) or { panic('ls failed on "${lib_dir}": ${err}') })
assert os.is_file(os.join_path(lib_dir, 'lib${expected_lib_name}.so'))
}
}

fn test_build_apk_way_1() {
vab, test_dir := setup_apk_build(@FN)

vab_cmd := [vab, '-o', test_dir, v_example('gg/worker_thread.v')].join(' ')
run(vab_cmd)

extract_and_check_apk('v_test_app', test_dir)
}

fn test_build_apk_way_2() {
vab, test_dir := setup_apk_build(@FN)

vab_cmd := [vab, v_example('sokol/particles'), '-o', test_dir].join(' ')
run(vab_cmd)

extract_and_check_apk('v_test_app', test_dir)
}

fn test_build_apk_way_3() {
vab, test_dir := setup_apk_build(@FN)

vab_cmd := [vab, '-f "-d trace_moves_spool_to_sbin"', v_example('sokol/particles'),
'-o', test_dir].join(' ')
run(vab_cmd)

extract_and_check_apk('v_test_app', test_dir)
}
122 changes: 122 additions & 0 deletions vabxt/vabxt.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright(C) 2019-2022 Lars Pontoppidan. All rights reserved.
// Use of this source code is governed by an MIT license file distributed with this software package
module vabxt

import os
import regex

// vabexe returns the path to the `vab` executable if found
// on the host platform, otherwise a blank `string`.
pub fn vabexe() string {
mut exe := os.getenv('VAB_EXE')
$if !windows {
if os.is_executable(exe) {
return os.real_path(exe)
}
possible_symlink := os.find_abs_path_of_executable('vab') or { '' }
if os.is_executable(possible_symlink) {
return os.real_path(possible_symlink)
}
vmodules_path := vmodules() or { '' }
if os.is_file(os.join_path(vmodules_path, 'vab', 'vab')) {
return os.join_path(vmodules_path, 'vab', 'vab')
}
} $else {
if os.exists(exe) {
return exe
}
system_path := os.find_abs_path_of_executable('vab') or { '' }
if os.exists(system_path) {
exe = system_path
}
if !os.exists(exe) {
res := os.execute('where.exe vab')
if res.exit_code != 0 {
exe = ''
} else {
return res.output.trim('\n\r')
}
}
vmodules_path := vmodules() or { '' }
if os.is_file(os.join_path(vmodules_path, 'vab', 'vab.exe')) {
return os.join_path(vmodules_path, 'vab', 'vab.exe')
}
}

return exe
}

// vmodules returns the path to the `.vmodules` folder if found
pub fn vmodules() !string {
mut vmodules_path := os.getenv('VMODULES')
if !os.is_dir(vmodules_path) {
vmodules_path = os.join_path(os.home_dir(), '.vmodules')
}
if !os.is_dir(vmodules_path) {
return error(@MOD + '.' + @FN + ': no valid v modules path found at "${vmodules_path}"')
}
return vmodules_path
}

pub fn found() bool {
return home() != ''
}

pub fn home() string {
// credits to @spytheman:
// https://discord.com/channels/592103645835821068/592294828432424960/746040606358503484
mut exe := vabexe()
$if !windows {
if os.is_executable(exe) {
return os.dir(exe)
}
} $else {
if os.exists(exe) {
exe = exe.replace('/', os.path_separator)
// Skip the `.bin\` dir
if os.dir(exe).ends_with('.bin') {
exe = os.dir(exe)
}
return os.dir(exe)
}
}
return ''
}

pub fn version() string {
mut version := ''
vab := vabexe()
if vab != '' {
vab_version := os.execute(vab + ' --version')
if vab_version.exit_code != 0 {
return version
}
output := vab_version.output
mut re := regex.regex_opt(r'.*(\d+\.?\d*\.?\d*)') or { panic(err) }
start, _ := re.match_string(output)
if start >= 0 && re.groups.len > 0 {
version = output[re.groups[0]..re.groups[1]]
}
return version
}
return '0.0.0'
}

pub fn version_commit_hash() string {
mut hash := ''
vab := vabexe()
if vab != '' {
vab_version := os.execute(vab + ' --version')
if vab_version.exit_code != 0 {
return ''
}
output := vab_version.output
mut re := regex.regex_opt(r'.*\d+\.?\d*\.?\d* ([a-fA-F0-9]{7,})') or { panic(err) }
start, _ := re.match_string(output)
if start >= 0 && re.groups.len > 0 {
hash = output[re.groups[0]..re.groups[1]]
}
return hash
}
return 'deadbeef'
}

0 comments on commit 2a5d023

Please sign in to comment.