mirror of
https://github.com/aljazceru/pubky-core-ffi.git
synced 2025-12-17 06:14:21 +01:00
docs: adds tests and updates docs
Adds several tests. Updates README.md with implementation instructions and usage examples.
This commit is contained in:
36
Cargo.lock
generated
36
Cargo.lock
generated
@@ -1332,6 +1332,24 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pubkymobile"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"pkarr",
|
||||
"pubky",
|
||||
"pubky-common",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tokio",
|
||||
"uniffi",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "2.2.3"
|
||||
@@ -1429,24 +1447,6 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "react_native_pubky"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"pkarr",
|
||||
"pubky",
|
||||
"pubky-common",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tokio",
|
||||
"uniffi",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.7"
|
||||
|
||||
11
Cargo.toml
11
Cargo.toml
@@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "react_native_pubky"
|
||||
name = "pubkymobile"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
crate_type = ["cdylib"]
|
||||
crate_type = ["cdylib", "rlib"]
|
||||
name = "pubkymobile"
|
||||
|
||||
[[bin]]
|
||||
@@ -27,4 +27,9 @@ base64 = "0.22.1"
|
||||
once_cell = "1.19.0"
|
||||
pubky = "0.3.0"
|
||||
pkarr = "2.2.1-alpha.2"
|
||||
pubky-common = "0.1.0"
|
||||
pubky-common = "0.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.40.0", features = ["full"] }
|
||||
serde_json = "1.0.114"
|
||||
hex = "0.4.3"
|
||||
265
README.md
265
README.md
@@ -1,5 +1,8 @@
|
||||
# pubky-core-mobile-sdk
|
||||
Pubky Core Mobile SDK
|
||||
# Pubky Core Mobile SDK
|
||||
|
||||
The Pubky Core Mobile SDK provides native bindings for iOS and Android platforms to interact with Pubky. This SDK allows you to perform operations like publishing content, retrieving data and managing authentication.
|
||||
|
||||
## Building the SDK
|
||||
|
||||
### To build both iOS and Android bindings:
|
||||
```
|
||||
@@ -14,4 +17,262 @@ Pubky Core Mobile SDK
|
||||
### To build only Android bindings:
|
||||
```
|
||||
./build.sh android
|
||||
```
|
||||
|
||||
## Run Tests:
|
||||
```
|
||||
cargo test -- --test-threads=1
|
||||
```
|
||||
|
||||
## iOS Integration
|
||||
|
||||
### Installation
|
||||
1. Add the XCFramework to your Xcode project:
|
||||
|
||||
- Drag bindings/ios/PubkyMobile.xcframework into your Xcode project
|
||||
Ensure "Copy items if needed" is checked
|
||||
Add the framework to your target
|
||||
|
||||
|
||||
2. Copy the Swift bindings:
|
||||
|
||||
- Add bindings/ios/pubkymobile.swift to your project
|
||||
|
||||
### Basic Usage
|
||||
```swift
|
||||
import PubkyMobile
|
||||
import PubkyMobile
|
||||
|
||||
class PubkyManager {
|
||||
// Generate a new secret key
|
||||
func generateNewAccount() throws -> String {
|
||||
let result = try generateSecretKey()
|
||||
guard let jsonData = result[1].data(using: .utf8),
|
||||
let json = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
|
||||
let secretKey = json["secret_key"] as? String else {
|
||||
throw NSError(domain: "PubkyError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to parse response"])
|
||||
}
|
||||
return secretKey
|
||||
}
|
||||
|
||||
// Sign up with a homeserver
|
||||
func signUp(secretKey: String, homeserver: String) async throws -> String {
|
||||
let result = try signUp(secretKey: secretKey, homeserver: homeserver)
|
||||
if result[0] == "error" {
|
||||
throw NSError(domain: "PubkyError", code: -1, userInfo: [NSLocalizedDescriptionKey: result[1]])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
|
||||
// Publish content
|
||||
func publishContent(recordName: String, content: String, secretKey: String) async throws -> String {
|
||||
let result = try publish(recordName: recordName, recordContent: content, secretKey: secretKey)
|
||||
if result[0] == "error" {
|
||||
throw NSError(domain: "PubkyError", code: -1, userInfo: [NSLocalizedDescriptionKey: result[1]])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
|
||||
// Retrieve content
|
||||
func getContent(url: String) async throws -> String {
|
||||
let result = try get(url: url)
|
||||
if result[0] == "error" {
|
||||
throw NSError(domain: "PubkyError", code: -1, userInfo: [NSLocalizedDescriptionKey: result[1]])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example Implementation
|
||||
```swift
|
||||
class ViewController: UIViewController {
|
||||
let pubkyManager = PubkyManager()
|
||||
|
||||
func setupAccount() async {
|
||||
do {
|
||||
// Generate new account
|
||||
let secretKey = try pubkyManager.generateNewAccount()
|
||||
|
||||
// Sign up with homeserver
|
||||
let homeserver = "pubky://8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo"
|
||||
let publicKey = try await pubkyManager.signUp(secretKey: secretKey, homeserver: homeserver)
|
||||
|
||||
// Publish content
|
||||
let content = "Hello, Pubky!"
|
||||
let recordName = "example.com"
|
||||
let publishResult = try await pubkyManager.publishContent(
|
||||
recordName: recordName,
|
||||
content: content,
|
||||
secretKey: secretKey
|
||||
)
|
||||
|
||||
print("Published with public key: \(publishResult)")
|
||||
} catch {
|
||||
print("Error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Android Integration
|
||||
|
||||
### Installation
|
||||
1. Add the JNI libraries to your project:
|
||||
|
||||
- Copy the contents of bindings/android/jniLibs to your project's app/src/main/jniLibs directory
|
||||
|
||||
|
||||
2. Add the Kotlin bindings:
|
||||
|
||||
- Copy bindings/android/pubkymobile.kt to your project's source directory
|
||||
|
||||
### Basic Usage
|
||||
```kotlin
|
||||
class PubkyManager {
|
||||
init {
|
||||
// Initialize the library
|
||||
System.loadLibrary("pubkymobile")
|
||||
}
|
||||
|
||||
fun generateNewAccount(): String {
|
||||
val result = generateSecretKey()
|
||||
if (result[0] == "error") {
|
||||
throw Exception(result[1])
|
||||
}
|
||||
val json = JSONObject(result[1])
|
||||
return json.getString("secret_key")
|
||||
}
|
||||
|
||||
suspend fun signUp(secretKey: String, homeserver: String): String {
|
||||
val result = signUp(secretKey, homeserver)
|
||||
if (result[0] == "error") {
|
||||
throw Exception(result[1])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
|
||||
suspend fun publishContent(recordName: String, content: String, secretKey: String): String {
|
||||
val result = publish(recordName, content, secretKey)
|
||||
if (result[0] == "error") {
|
||||
throw Exception(result[1])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
|
||||
suspend fun getContent(url: String): String {
|
||||
val result = get(url)
|
||||
if (result[0] == "error") {
|
||||
throw Exception(result[1])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example Implementation
|
||||
```kotlin
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private val pubkyManager = PubkyManager()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
// Generate new account
|
||||
val secretKey = pubkyManager.generateNewAccount()
|
||||
|
||||
// Sign up with homeserver
|
||||
val homeserver = "pubky://8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo"
|
||||
val publicKey = pubkyManager.signUp(secretKey, homeserver)
|
||||
|
||||
// Publish content
|
||||
val content = "Hello, Pubky!"
|
||||
val recordName = "example.com"
|
||||
val publishResult = pubkyManager.publishContent(
|
||||
recordName = recordName,
|
||||
content = content,
|
||||
secretKey = secretKey
|
||||
)
|
||||
|
||||
Log.d("Pubky", "Published with public key: $publishResult")
|
||||
} catch (e: Exception) {
|
||||
Log.e("Pubky", "Error: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Working with HTTPS Records
|
||||
|
||||
```swift
|
||||
// iOS
|
||||
func publishHttps(recordName: String, target: String, secretKey: String) async throws -> String {
|
||||
let result = try publishHttps(recordName: recordName, target: target, secretKey: secretKey)
|
||||
if result[0] == "error" {
|
||||
throw NSError(domain: "PubkyError", code: -1, userInfo: [NSLocalizedDescriptionKey: result[1]])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
```
|
||||
|
||||
```kotlin
|
||||
// Android
|
||||
suspend fun publishHttps(recordName: String, target: String, secretKey: String): String {
|
||||
val result = publishHttps(recordName, target, secretKey)
|
||||
if (result[0] == "error") {
|
||||
throw Exception(result[1])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
```
|
||||
|
||||
### Recovery File Management
|
||||
```swift
|
||||
// iOS
|
||||
func createRecoveryFile(secretKey: String, passphrase: String) throws -> String {
|
||||
let result = try createRecoveryFile(secretKey: secretKey, passphrase: passphrase)
|
||||
if result[0] == "error" {
|
||||
throw NSError(domain: "PubkyError", code: -1, userInfo: [NSLocalizedDescriptionKey: result[1]])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
```
|
||||
|
||||
```kotlin
|
||||
// iOS
|
||||
func createRecoveryFile(secretKey: String, passphrase: String) throws -> String {
|
||||
let result = try createRecoveryFile(secretKey: secretKey, passphrase: passphrase)
|
||||
if result[0] == "error" {
|
||||
throw NSError(domain: "PubkyError", code: -1, userInfo: [NSLocalizedDescriptionKey: result[1]])
|
||||
}
|
||||
return result[1]
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
All methods return a `Vec<String>` where:
|
||||
- The first element ([0]) is either "success" or "error"
|
||||
- The second element ([1]) contains either the result data or error message
|
||||
|
||||
It's recommended to wrap all calls in try-catch blocks and handle errors appropriately in your application.
|
||||
|
||||
## Network Configuration
|
||||
|
||||
You can switch between default and testnet:
|
||||
```swift
|
||||
// iOS
|
||||
try switchNetwork(useTestnet: true) // For testnet
|
||||
try switchNetwork(useTestnet: false) // For default
|
||||
```
|
||||
|
||||
```kotlin
|
||||
// Android
|
||||
switchNetwork(true) // For testnet
|
||||
switchNetwork(false) // For default
|
||||
```
|
||||
@@ -67,7 +67,7 @@ pub fn get_pubky_client() -> Arc<PubkyClient> {
|
||||
#[uniffi::export]
|
||||
pub fn switch_network(use_testnet: bool) -> Vec<String> {
|
||||
NETWORK_CLIENT.switch_network(use_testnet);
|
||||
create_response_vector(false, format!("Switched to {} network", if use_testnet { "testnet" } else { "mainnet" }))
|
||||
create_response_vector(false, format!("Switched to {} network", if use_testnet { "testnet" } else { "default" }))
|
||||
}
|
||||
|
||||
static TOKIO_RUNTIME: Lazy<Arc<Runtime>> = Lazy::new(|| {
|
||||
|
||||
27
tests/common/mod.rs
Normal file
27
tests/common/mod.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use std::string::ToString;
|
||||
use std::sync::Arc;
|
||||
use once_cell::sync::Lazy;
|
||||
use pubky::PubkyClient;
|
||||
use pkarr::Keypair;
|
||||
|
||||
pub static TEST_CLIENT: Lazy<Arc<PubkyClient>> = Lazy::new(|| {
|
||||
Arc::new(PubkyClient::default())
|
||||
});
|
||||
|
||||
//pub const HOMESERVER: &str = "8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo";
|
||||
pub const HOMESERVER: &str = "ufibwbmed6jeq9k4p583go95wofakh9fwpp4k734trq79pd9u1uy";
|
||||
|
||||
// For tests that need a consistent keypair
|
||||
pub static SHARED_KEYPAIR: Lazy<Keypair> = Lazy::new(Keypair::random);
|
||||
|
||||
// For tests that need fresh keypairs
|
||||
pub fn generate_test_keypair() -> Keypair {
|
||||
Keypair::random()
|
||||
}
|
||||
|
||||
pub fn get_test_setup() -> (Keypair, String, String) {
|
||||
let keypair = SHARED_KEYPAIR.clone();
|
||||
let secret_key = hex::encode(keypair.secret_key());
|
||||
let homeserver = HOMESERVER.to_string();
|
||||
(keypair, secret_key, homeserver)
|
||||
}
|
||||
227
tests/lib_tests.rs
Normal file
227
tests/lib_tests.rs
Normal file
@@ -0,0 +1,227 @@
|
||||
use pubkymobile::*;
|
||||
use tokio;
|
||||
use base64;
|
||||
|
||||
mod common;
|
||||
use crate::common::{get_test_setup};
|
||||
|
||||
// Test keypair generation
|
||||
#[test]
|
||||
fn test_put_and_get_and_list() {
|
||||
let (keypair, secret_key, homeserver) = get_test_setup();
|
||||
|
||||
let public_key = keypair.public_key().to_string();
|
||||
let url = format!("pubky://{}/pub/test.com/testfile", public_key);
|
||||
let content = "test content".to_string();
|
||||
|
||||
let sign_up_result = sign_up(secret_key, homeserver);
|
||||
assert_eq!(sign_up_result[0], "success");
|
||||
|
||||
let inner_url = url.clone();
|
||||
|
||||
let put_result = put(url.clone(), content.clone());
|
||||
assert_eq!(put_result[0], "success");
|
||||
|
||||
// Add a small delay to ensure the put operation completes
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
|
||||
let get_result = get(url);
|
||||
assert_eq!(get_result[0], "success");
|
||||
assert_eq!(get_result[1], content);
|
||||
|
||||
let list_result = list(inner_url);
|
||||
println!("List result: {:?}", list_result);
|
||||
assert_eq!(list_result[0], "success");
|
||||
|
||||
let json: serde_json::Value = serde_json::from_str(&list_result[1]).unwrap();
|
||||
assert!(json.is_array());
|
||||
|
||||
if let Some(url_str) = json.as_array().and_then(|arr| arr.get(0)).and_then(|v| v.as_str()) {
|
||||
assert!(url_str.contains(&public_key));
|
||||
} else {
|
||||
panic!("Expected array with URL string");
|
||||
}
|
||||
}
|
||||
|
||||
// Test generate secret key
|
||||
#[tokio::test]
|
||||
async fn test_generate_secret_key() {
|
||||
let result = generate_secret_key();
|
||||
assert_eq!(result[0], "success");
|
||||
|
||||
let json: serde_json::Value = serde_json::from_str(&result[1]).unwrap();
|
||||
|
||||
assert!(json["secret_key"].is_string());
|
||||
assert!(json["public_key"].is_string());
|
||||
assert!(json["uri"].is_string());
|
||||
}
|
||||
|
||||
// Test get public key from secret key
|
||||
#[tokio::test]
|
||||
async fn test_get_public_key_from_secret_key() {
|
||||
let (_, secret_key, _) = get_test_setup();
|
||||
|
||||
let result = get_public_key_from_secret_key(secret_key);
|
||||
assert_eq!(result[0], "success");
|
||||
|
||||
let json: serde_json::Value = serde_json::from_str(&result[1]).unwrap();
|
||||
assert!(json["public_key"].is_string());
|
||||
assert!(json["uri"].is_string());
|
||||
|
||||
// Test with invalid secret key
|
||||
let result = get_public_key_from_secret_key("invalid_key".to_string());
|
||||
assert_eq!(result[0], "error");
|
||||
}
|
||||
|
||||
// Test sign up functionality
|
||||
#[test]
|
||||
fn test_publish_and_resolve() {
|
||||
let (keypair, secret_key, _) = get_test_setup();
|
||||
let record_name = "test.record".to_string();
|
||||
let record_content = "test content".to_string();
|
||||
|
||||
// Test publish
|
||||
let publish_result = publish(record_name.clone(), record_content.clone(), secret_key.clone());
|
||||
assert_eq!(publish_result[0], "success");
|
||||
|
||||
// Test resolve
|
||||
let public_key = keypair.public_key().to_string();
|
||||
let resolve_result = resolve(public_key);
|
||||
assert_eq!(resolve_result[0], "success");
|
||||
|
||||
let json: serde_json::Value = serde_json::from_str(&resolve_result[1]).unwrap();
|
||||
assert!(json["records"].is_array());
|
||||
}
|
||||
|
||||
// Test recovery file creation and decryption
|
||||
#[tokio::test]
|
||||
async fn test_create_and_decrypt_recovery_file() {
|
||||
let (_, secret_key, _) = get_test_setup();
|
||||
let passphrase = "test_passphrase".to_string();
|
||||
|
||||
// Create recovery file
|
||||
let create_result = create_recovery_file(secret_key.clone(), passphrase.clone());
|
||||
assert_eq!(create_result[0], "success");
|
||||
|
||||
// Test recovery file decryption
|
||||
let recovery_file = create_result[1].clone();
|
||||
let decrypt_result = decrypt_recovery_file(recovery_file, passphrase);
|
||||
assert_eq!(decrypt_result[0], "success");
|
||||
assert_eq!(decrypt_result[1], secret_key);
|
||||
}
|
||||
|
||||
// Test HTTPS publishing functionality
|
||||
#[test]
|
||||
fn test_publish_https() {
|
||||
let (_, secret_key, _) = get_test_setup();
|
||||
let record_name = "test.domain".to_string();
|
||||
let target = "target.domain".to_string();
|
||||
|
||||
let result = publish_https(record_name, target, secret_key);
|
||||
assert_eq!(result[0], "success");
|
||||
}
|
||||
|
||||
// Test resolve HTTPS functionality
|
||||
#[test]
|
||||
fn test_resolve_https() {
|
||||
let (keypair, _, _) = get_test_setup();
|
||||
let public_key = keypair.public_key().to_string();
|
||||
|
||||
let result = resolve_https(public_key);
|
||||
// Note: This might be "error" if no HTTPS records exist
|
||||
assert!(result[0] == "success" || result[0] == "error");
|
||||
}
|
||||
|
||||
// Test sign in functionality
|
||||
#[test]
|
||||
fn test_sign_in_and_out() {
|
||||
let (_, secret_key, _) = get_test_setup();
|
||||
|
||||
// Test sign in
|
||||
let sign_in_result = sign_in(secret_key.clone());
|
||||
assert_eq!(sign_in_result[0], "success");
|
||||
assert_eq!(sign_in_result[1], "Sign in success");
|
||||
|
||||
// Test sign out
|
||||
let sign_out_result = sign_out(secret_key);
|
||||
assert_eq!(sign_out_result[0], "success");
|
||||
assert_eq!(sign_out_result[1], "Sign out success");
|
||||
}
|
||||
|
||||
// Test delete functionality
|
||||
#[test]
|
||||
fn test_delete() {
|
||||
let (keypair, secret_key, homeserver) = get_test_setup();
|
||||
|
||||
// First sign up
|
||||
let sign_up_result = sign_up(secret_key.clone(), homeserver);
|
||||
assert_eq!(sign_up_result[0], "success");
|
||||
|
||||
let public_key = keypair.public_key().to_string();
|
||||
let url = format!("pubky://{}/pub/test.com/testfile", public_key);
|
||||
let content = "test content".to_string();
|
||||
|
||||
// Put some content first
|
||||
let put_result = put(url.clone(), content);
|
||||
assert_eq!(put_result[0], "success");
|
||||
|
||||
// Test delete
|
||||
let delete_result = delete_file(url.clone());
|
||||
assert_eq!(delete_result[0], "success");
|
||||
assert_eq!(delete_result[1], "Deleted successfully");
|
||||
|
||||
// Verify deletion by trying to get the file
|
||||
let get_result = get(url);
|
||||
assert_eq!(get_result[0], "error");
|
||||
}
|
||||
|
||||
// Test network switching
|
||||
#[test]
|
||||
fn test_switch_network() {
|
||||
// Test switching to testnet
|
||||
let testnet_result = switch_network(true);
|
||||
println!("Testnet result: {:?}", testnet_result);
|
||||
assert_eq!(testnet_result[0], "success");
|
||||
assert_eq!(testnet_result[1], "Switched to testnet network");
|
||||
|
||||
// Add a small delay to ensure the put operation completes
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
|
||||
// Test switching back to default
|
||||
let default_result = switch_network(false);
|
||||
println!("Default network result: {:?}", default_result);
|
||||
assert_eq!(default_result[0], "success");
|
||||
assert_eq!(default_result[1], "Switched to default network");
|
||||
}
|
||||
|
||||
// Test auth URL parsing
|
||||
#[test]
|
||||
fn test_parse_auth_url() {
|
||||
let test_url = "pubkyauth:///?caps=/pub/pubky.app/:rw,/pub/foo.bar/file:r&secret=U55XnoH6vsMCpx1pxHtt8fReVg4Brvu9C0gUBuw-Jkw&relay=http://167.86.102.121:4173/";
|
||||
let result = parse_auth_url(test_url.to_string());
|
||||
println!("test_parse_auth_url Result: {:?}", result);
|
||||
assert_eq!(result[0], "success");
|
||||
|
||||
let json: serde_json::Value = serde_json::from_str(&result[1]).unwrap();
|
||||
assert!(json.is_object());
|
||||
}
|
||||
|
||||
// Test error cases
|
||||
#[test]
|
||||
fn test_error_cases() {
|
||||
// Test invalid secret key
|
||||
let sign_in_result = sign_in("invalid_key".to_string());
|
||||
assert_eq!(sign_in_result[0], "error");
|
||||
|
||||
// Test invalid URL
|
||||
let get_result = get("invalid_url".to_string());
|
||||
assert_eq!(get_result[0], "error");
|
||||
|
||||
// Test invalid public key for resolve
|
||||
let resolve_result = resolve("invalid_public_key".to_string());
|
||||
assert_eq!(resolve_result[0], "error");
|
||||
|
||||
// Test empty recovery file creation
|
||||
let recovery_result = create_recovery_file("".to_string(), "passphrase".to_string());
|
||||
assert_eq!(recovery_result[0], "error");
|
||||
}
|
||||
Reference in New Issue
Block a user