Skip to content
Merged
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
126 changes: 112 additions & 14 deletions .github/workflows/linux-ci-rust.yml → .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Linux CI Rust
name: Rust CI

on:
push:
Expand All @@ -16,7 +16,7 @@ concurrency:

jobs:
# Check formatting, clippy warnings, run tests and check code coverage.
build-and-test:
rust-lints:
permissions:
contents: read
checks: write
Expand Down Expand Up @@ -51,18 +51,6 @@ jobs:
cargo clippy -- -D warnings
working-directory: rust

- name: Run tests
run: |
tools/rust-coverage

- name: Gather and check Rust code coverage
run: |
tools/check-coverage rust/coverage.stats rust/coverage.info

- name: Run Doc tests
run: |
tools/rust-test doc

# Run Rust tests in WASM.
test-wasm:
runs-on: ubuntu-24.04
Expand Down Expand Up @@ -163,3 +151,113 @@ jobs:
comment-author: 'github-actions[bot]'
edit-mode: replace
body-path: 'report-diff.md'

memory-profiler:
runs-on: ubuntu-24.04
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.8

- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
workspaces: |
rust

- name: Install llvm
run: |
# to get the symbolizer for debug symbol resolution
sudo apt install llvm

- name: Install nightly
uses: dtolnay/rust-toolchain@nightly

- name: Enable debug symbols
run: |
cd rust
# to fix buggy leak analyzer:
# https://github.com/japaric/rust-san#unrealiable-leaksanitizer
# ensure there's a profile.dev section
if ! grep -qE '^[ \t]*[profile.dev]' Cargo.toml; then
echo >> Cargo.toml
echo '[profile.dev]' >> Cargo.toml
fi
# remove pre-existing opt-levels in profile.dev
sed -i '/^\s*\[profile.dev\]/,/^\s*\[/ {/^\s*opt-level/d}' Cargo.toml
# now set opt-level to 1
sed -i '/^\s*\[profile.dev\]/a opt-level = 1' Cargo.toml
cat Cargo.toml

- name: cargo test -Zsanitizer=address
# only --lib --tests b/c of https://github.com/rust-lang/rust/issues/53945
run: |
cd rust
cargo test --lib --tests --all-features --target x86_64-unknown-linux-gnu
env:
ASAN_OPTIONS: "detect_odr_violation=0:detect_leaks=0"
RUSTFLAGS: "-Z sanitizer=address"

- name: cargo test -Zsanitizer=leak
if: always()
run: |
cd rust
cargo test --all-features --target x86_64-unknown-linux-gnu
env:
RUSTFLAGS: "-Z sanitizer=leak"

coverage:
runs-on: ubuntu-24.04
if: github.event.pull_request.draft == false

steps:
- uses: actions/checkout@v3
- name: Install system dependencies
run: |
tools/install-sys-dependencies-linux

- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.8

- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
workspaces: |
rust

- name: Install Rust dependencies
run: |
tools/install-rust-dependencies dev

- name: cargo generate-lockfile
if: hashFiles('Cargo.lock') == ''
run: |
cd rust
cargo generate-lockfile

- name: Run tests
run: |
tools/rust-coverage

- name: Run Doc tests
run: |
tools/rust-test doc

- name: Record Rust version
run: echo "RUST=$(rustc --version)" >> "$GITHUB_ENV"

# TODO: Uncomment this when we have a codecov token
# - name: Upload to codecov.io
# uses: codecov/codecov-action@v5
# with:
# fail_ci_if_error: true
# token: ${{ secrets.CODECOV_TOKEN }}
# env_vars: OS,RUST

- name: Gather and check Rust code coverage
run: |
tools/check-coverage rust/coverage.stats rust/lcov.info
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ emsdk/
wasm-build/

# Code coverage files
lcov.info
coverage.info
coverage/
swift/test_output/
Expand Down
2 changes: 1 addition & 1 deletion android/gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
case "$( uname -s )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
Expand Down
2 changes: 1 addition & 1 deletion bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ if isHelp; then
fi

echo "#### Installing system dependencies ... ####"
if [[ $(uname) == "Darwin" ]]; then
if [[ $(uname -s) == "Darwin" ]]; then
tools/install-sys-dependencies-mac
else
tools/install-sys-dependencies-linux
Expand Down
2 changes: 1 addition & 1 deletion kotlin/gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
case "$( uname -s )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
Expand Down
20 changes: 12 additions & 8 deletions rust/tw_encoding/tests/base32_ffi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ use tw_encoding::ffi::{decode_base32, encode_base32};
/// equals to `expected`.
#[track_caller]
fn test_base32_encode_helper(input: &[u8], expected: &str, alphabet: Option<&str>, padding: bool) {
let alphabet = alphabet
.map(|alphabet| CString::new(alphabet).unwrap().into_raw())
.unwrap_or_else(std::ptr::null_mut);
let alphabet_cstring = alphabet.map(|alphabet| CString::new(alphabet).unwrap());
let alphabet_ptr = alphabet_cstring
.as_ref()
.map(|s| s.as_ptr())
.unwrap_or_else(std::ptr::null);

let result_ptr =
unsafe { encode_base32(input.as_ptr(), input.len(), alphabet, padding) }.unwrap();
unsafe { encode_base32(input.as_ptr(), input.len(), alphabet_ptr, padding) }.unwrap();
let result = unsafe { CString::from_raw(result_ptr) };
assert_eq!(result.to_str().unwrap(), expected);
}
Expand All @@ -24,12 +26,14 @@ fn test_base32_encode_helper(input: &[u8], expected: &str, alphabet: Option<&str
#[track_caller]
fn test_base32_decode_helper(input: &str, expected: &[u8], alphabet: Option<&str>, padding: bool) {
let input = CString::new(input).unwrap();
let alphabet = alphabet
.map(|alphabet| CString::new(alphabet).unwrap().into_raw())
.unwrap_or_else(std::ptr::null_mut);
let alphabet_cstring = alphabet.map(|alphabet| CString::new(alphabet).unwrap());
let alphabet_ptr = alphabet_cstring
.as_ref()
.map(|s| s.as_ptr())
.unwrap_or_else(std::ptr::null);

let decoded = unsafe {
decode_base32(input.as_ptr(), alphabet, padding)
decode_base32(input.as_ptr(), alphabet_ptr, padding)
.unwrap()
.into_vec()
};
Expand Down
31 changes: 18 additions & 13 deletions rust/tw_encoding/tests/base64_ffi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@
//
// Copyright © 2017 Trust Wallet.

use std::ffi::{CStr, CString};
use std::ffi::CString;
use tw_encoding::ffi::{decode_base64, encode_base64};

#[test]
fn test_encode_base64() {
let data = b"hello world";
let encoded = unsafe { CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), false)) };
let result_ptr = unsafe { encode_base64(data.as_ptr(), data.len(), false) };
let result = unsafe { CString::from_raw(result_ptr) };
let expected = "aGVsbG8gd29ybGQ=";
assert_eq!(encoded.to_str().unwrap(), expected);
assert_eq!(result.to_str().unwrap(), expected);
}

#[test]
fn test_encode_base64_url() {
let data = b"+'?ab";
let encoded = unsafe { CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), true)) };
let result_ptr = unsafe { encode_base64(data.as_ptr(), data.len(), true) };
let result = unsafe { CString::from_raw(result_ptr) };
let expected = "Kyc_YWI=";
assert_eq!(encoded.to_str().unwrap(), expected);
assert_eq!(result.to_str().unwrap(), expected);
}

#[test]
Expand All @@ -27,9 +29,11 @@ fn test_decode_base64_url() {
let expected = b"+'?ab";

let encoded_c_str = CString::new(encoded).unwrap();
let encoded_ptr = encoded_c_str.as_ptr();

let decoded = unsafe { decode_base64(encoded_ptr, true).unwrap().into_vec() };
let decoded = unsafe {
decode_base64(encoded_c_str.as_ptr(), true)
.unwrap()
.into_vec()
};
assert_eq!(decoded, expected);
}

Expand All @@ -39,17 +43,18 @@ fn test_decode_base64() {
let expected = b"hello world!";

let encoded_c_str = CString::new(encoded).unwrap();
let encoded_ptr = encoded_c_str.as_ptr();

let decoded = unsafe { decode_base64(encoded_ptr, false).unwrap().into_vec() };
let decoded = unsafe {
decode_base64(encoded_c_str.as_ptr(), false)
.unwrap()
.into_vec()
};
assert_eq!(decoded, expected);
}

#[test]
fn test_decode_base64_invalid() {
let invalid_encoded = "_This_is_an_invalid_base64_";
let encoded_c_str = CString::new(invalid_encoded).unwrap();
let encoded_ptr = encoded_c_str.as_ptr();
let res = unsafe { decode_base64(encoded_ptr, false) };
let res = unsafe { decode_base64(encoded_c_str.as_ptr(), false) };
assert!(res.is_err());
}
20 changes: 9 additions & 11 deletions rust/tw_encoding/tests/hex_ffi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@
//
// Copyright © 2017 Trust Wallet.

use std::ffi::{CStr, CString};
use std::ffi::CString;
use tw_encoding::ffi::{decode_hex, encode_hex};

#[test]
fn test_encode_hex_without_prefix() {
let data = b"hello world";
let encoded = unsafe { CStr::from_ptr(encode_hex(data.as_ptr(), data.len(), false)) };
let result_ptr = unsafe { encode_hex(data.as_ptr(), data.len(), false) };
let result = unsafe { CString::from_raw(result_ptr) };
let expected = "68656c6c6f20776f726c64";
assert_eq!(encoded.to_str().unwrap(), expected);
assert_eq!(result.to_str().unwrap(), expected);
}

#[test]
fn test_encode_hex_with_prefix() {
let data = b"hello world";
let encoded = unsafe { CStr::from_ptr(encode_hex(data.as_ptr(), data.len(), true)) };
let result_ptr = unsafe { encode_hex(data.as_ptr(), data.len(), true) };
let result = unsafe { CString::from_raw(result_ptr) };
let expected = "0x68656c6c6f20776f726c64";
assert_eq!(encoded.to_str().unwrap(), expected);
assert_eq!(result.to_str().unwrap(), expected);
}

#[test]
fn test_decode_hex() {
let encoded = "68656c6c6f20776f726c64";

let encoded_c_str = CString::new(encoded).unwrap();
let encoded_ptr = encoded_c_str.as_ptr();

let decoded: Vec<_> = unsafe { decode_hex(encoded_ptr).unwrap().into_vec() };
let decoded: Vec<_> = unsafe { decode_hex(encoded_c_str.as_ptr()).unwrap().into_vec() };
assert_eq!(decoded, b"hello world");
}

Expand All @@ -37,8 +37,6 @@ fn test_decode_hex_with_prefix() {
let encoded = "0x68656c6c6f20776f726c64";

let encoded_c_str = CString::new(encoded).unwrap();
let encoded_ptr = encoded_c_str.as_ptr();

let decoded: Vec<_> = unsafe { decode_hex(encoded_ptr).unwrap().into_vec() };
let decoded: Vec<_> = unsafe { decode_hex(encoded_c_str.as_ptr()).unwrap().into_vec() };
assert_eq!(decoded, b"hello world");
}
6 changes: 5 additions & 1 deletion rust/tw_tests/tests/utils/bit_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use tw_encoding::hex::{DecodeHex, ToHex};
use tw_memory::test_utils::tw_data_helper::TWDataHelper;
use wallet_core_rs::ffi::utils::bit_reader_ffi::{
tw_bit_reader_create, tw_bit_reader_finished, tw_bit_reader_read_u8,
tw_bit_reader_create, tw_bit_reader_delete, tw_bit_reader_finished, tw_bit_reader_read_u8,
tw_bit_reader_read_u8_slice, CBitReaderCode,
};

Expand Down Expand Up @@ -37,6 +37,8 @@ fn test_tw_bit_reader_success() {
);

assert!(unsafe { tw_bit_reader_finished(reader) });

unsafe { tw_bit_reader_delete(reader) };
}

#[test]
Expand Down Expand Up @@ -66,4 +68,6 @@ fn test_tw_bit_reader_error() {
res.into_result().unwrap_err(),
CBitReaderCode::NotEnoughData as i32
);

unsafe { tw_bit_reader_delete(reader) };
}
Loading
Loading