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
64 changes: 64 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Tests

on:
push:
branches:
- main
- "v*-dev"
pull_request:

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Test Suite
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-test-
${{ runner.os }}-cargo-
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
Comment on lines +35 to +38
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actions-rs/toolchain@v1 action is deprecated. Consider using dtolnay/rust-toolchain or actions/setup-rust instead for better maintenance and security.

Suggested change
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
uses: dtolnay/rust-toolchain@stable

Copilot uses AI. Check for mistakes.

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential pkg-config clang cmake libsqlite3-dev
- name: Install protoc
run: |
curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v25.2/protoc-25.2-linux-x86_64.zip
sudo unzip -o protoc-25.2-linux-x86_64.zip -d /usr/local bin/protoc
sudo unzip -o protoc-25.2-linux-x86_64.zip -d /usr/local 'include/*'
rm -f protoc-25.2-linux-x86_64.zip
env:
PROTOC: /usr/local/bin/protoc

- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features --workspace

- name: Run doc tests
uses: actions-rs/cargo@v1
with:
command: test
args: --doc --all-features --workspace
1 change: 1 addition & 0 deletions src/ui/tokens/tokens_screen/distributions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ impl TokensScreen {
DistributionFunctionUI::InvertedLogarithmic,
"InvertedLogarithmic",
);
// DistributionFunctionUI::Random is not supported
});

let response = crate::ui::helpers::info_icon_button(ui, "Info about distribution types");
Expand Down
53 changes: 29 additions & 24 deletions src/ui/tokens/tokens_screen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,9 +1061,9 @@ pub struct TokensScreen {
// --- FixedAmount ---
pub fixed_amount_input: String,

// --- Random ---
pub random_min_input: String,
pub random_max_input: String,
// --- Random --- - not supported
// pub random_min_input: String,
// pub random_max_input: String,

// --- StepDecreasingAmount ---
pub step_count_input: String,
Expand Down Expand Up @@ -1406,8 +1406,8 @@ impl TokensScreen {
perpetual_dist_interval_unit: IntervalTimeUnit::Day,
perpetual_dist_function: DistributionFunctionUI::FixedAmount,
fixed_amount_input: String::new(),
random_min_input: String::new(),
random_max_input: String::new(),
// random_min_input: String::new(),
// random_max_input: String::new(),
step_count_input: String::new(),
decrease_per_interval_numerator_input: String::new(),
decrease_per_interval_denominator_input: String::new(),
Expand Down Expand Up @@ -2133,8 +2133,8 @@ impl TokensScreen {
self.perpetual_dist_type = PerpetualDistributionIntervalTypeUI::None;
self.perpetual_dist_interval_input = "".to_string();
self.fixed_amount_input = "".to_string();
self.random_min_input = "".to_string();
self.random_max_input = "".to_string();
// self.random_min_input = "".to_string();
// self.random_max_input = "".to_string();
self.step_count_input = "".to_string();
self.decrease_per_interval_numerator_input = "".to_string();
self.decrease_per_interval_denominator_input = "".to_string();
Expand Down Expand Up @@ -2854,6 +2854,7 @@ impl ScreenWithWalletUnlock for TokensScreen {
mod tests {
use std::path::Path;

use crate::app_dir::copy_env_file_if_not_exists;
use crate::database::Database;
use crate::model::qualified_identity::IdentityStatus;
use crate::model::qualified_identity::encrypted_key_storage::KeyStorage;
Expand Down Expand Up @@ -2892,6 +2893,7 @@ mod tests {
let db = Arc::new(Database::new(db_file_path).unwrap());
db.initialize(Path::new(&db_file_path)).unwrap();

copy_env_file_if_not_exists(); // Required by AppContext::new()
let app_context = AppContext::new(Network::Regtest, db, None, Default::default())
.expect("Expected to create AppContext");
let mut token_creator_ui = TokensScreen::new(&app_context, TokensSubscreen::TokenCreator);
Expand Down Expand Up @@ -3005,7 +3007,7 @@ mod tests {
// -------------------------------------------------
// Groups
// -------------------------------------------------
// We'll define 2 groups for testing: positions 2 (main) and 7
// We'll define 2 groups for testing: positions 0 (main) and 1
token_creator_ui.groups_ui = vec![
GroupConfigUI {
required_power_str: "2".to_string(),
Expand Down Expand Up @@ -3165,25 +3167,26 @@ mod tests {
};
assert_eq!(
new_dest_id.to_string(Encoding::Base58),
"GCMnPwQZcH3RP9atgkmvtmN45QrVcYvh5cmUYARHBTu9"
"BCMnPwQZcH3RP9atgkmvtmN45QrVcYvh5cmUYARHBTu9"
);
assert!(dist_rules_v0.minting_allow_choosing_destination);

// F) Check the Groups
// (Positions 2 and 7, from above)
// (Positions 0 and 1, from above)
assert_eq!(contract_v1.groups.len(), 2, "We added two groups in the UI");
let group2 = contract_v1.groups.get(&2).expect("Expected group pos=2");

let group0 = contract_v1.groups.get(&0).expect("Expected group pos=0");
assert_eq!(
group2.required_power(),
group0.required_power(),
2,
"Group #2 required_power mismatch"
"Group #0 required_power mismatch"
);
let members = &group2.members();
let members = &group0.members();
assert_eq!(members.len(), 2);

let group7 = contract_v1.groups.get(&7).expect("Expected group pos=7");
assert_eq!(group7.required_power(), 1);
assert_eq!(group7.members().len(), 0);
let group1 = contract_v1.groups.get(&1).expect("Expected group pos=1");
assert_eq!(group1.required_power(), 1);
assert_eq!(group1.members().len(), 0);
}

#[test]
Expand All @@ -3192,6 +3195,7 @@ mod tests {
let db = Arc::new(Database::new(db_file_path).unwrap());
db.initialize(Path::new(&db_file_path)).unwrap();

copy_env_file_if_not_exists(); // required by AppContext::new()
let app_context = AppContext::new(Network::Regtest, db, None, Default::default())
.expect("Expected to create AppContext");
let mut token_creator_ui = TokensScreen::new(&app_context, TokensSubscreen::TokenCreator);
Expand Down Expand Up @@ -3238,9 +3242,10 @@ mod tests {
// Enable perpetual distribution, select Random
token_creator_ui.enable_perpetual_distribution = true;
token_creator_ui.perpetual_dist_type = PerpetualDistributionIntervalTypeUI::TimeBased;
token_creator_ui.perpetual_dist_interval_input = "60000".to_string();
token_creator_ui.random_min_input = "100".to_string();
token_creator_ui.random_max_input = "200".to_string();
token_creator_ui.perpetual_dist_function = DistributionFunctionUI::FixedAmount;
token_creator_ui.perpetual_dist_interval_input = "60".to_string();
token_creator_ui.perpetual_dist_interval_unit = IntervalTimeUnit::Second;
token_creator_ui.fixed_amount_input = "100".to_string();

// Parse + build
let build_args = token_creator_ui
Expand Down Expand Up @@ -3289,11 +3294,10 @@ mod tests {
RewardDistributionType::TimeBasedDistribution { interval, function } => {
assert_eq!(*interval, 60000, "Expected 60s (in ms)");
match function {
DistributionFunction::Random { min, max } => {
assert_eq!(*min, 100);
assert_eq!(*max, 200);
DistributionFunction::FixedAmount { amount } => {
assert_eq!(*amount, 100);
}
_ => panic!("Expected DistributionFunction::Random"),
_ => panic!("Expected DistributionFunction::FixedAmount"),
}
}
_ => panic!("Expected TimeBasedDistribution"),
Expand All @@ -3306,6 +3310,7 @@ mod tests {
let db = Arc::new(Database::new(db_file_path).unwrap());
db.initialize(Path::new(&db_file_path)).unwrap();

copy_env_file_if_not_exists(); // required by AppContext::new()
let app_context = AppContext::new(Network::Regtest, db, None, Default::default())
.expect("Expected to create AppContext");
let mut token_creator_ui = TokensScreen::new(&app_context, TokensSubscreen::TokenCreator);
Expand Down
25 changes: 11 additions & 14 deletions src/utils/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,21 @@ use std::path::Path;
/// - If the path ends with `.app/Contents/MacOS/Dash-Qt`, it displays as `Dash-Qt.app`
/// - Otherwise, it displays the full path
///
/// # Examples
/// ```no_run
/// "/Applications/Dash-Qt.app/Contents/MacOS/Dash-Qt" -> "Dash-Qt.app"
/// "/usr/local/bin/dash-qt" -> "/usr/local/bin/dash-qt"
/// ```
/// # Examples:
///
/// * `"/Applications/Dash-Qt.app/Contents/MacOS/Dash-Qt" -> "Dash-Qt.app"`
/// * `"/usr/local/bin/dash-qt" -> "/usr/local/bin/dash-qt"`
pub fn format_path_for_display(path: &Path) -> String {
let path_str = path.to_string_lossy();

// Check if this is a macOS app bundle executable path
if cfg!(target_os = "macos") {
// Check if the path matches the pattern for an app bundle executable
if let Some(app_start) = path_str.rfind(".app/Contents/MacOS/") {
// Find the start of the app name by looking backwards for a path separator
let before_app = &path_str[..app_start];
let app_name_start = before_app.rfind('/').map(|i| i + 1).unwrap_or(0);
let app_name = &path_str[app_name_start..app_start + 4]; // Include ".app"
return app_name.to_string();
}
// Check if the path matches the pattern for an app bundle executable
if let Some(app_start) = path_str.rfind(".app/Contents/MacOS/") {
// Find the start of the app name by looking backwards for a path separator
let before_app = &path_str[..app_start];
let app_name_start = before_app.rfind('/').map(|i| i + 1).unwrap_or(0);
let app_name = &path_str[app_name_start..app_start + 4]; // Include ".app"
return app_name.to_string();
}

// For all other cases, return the full path
Expand Down
Loading