How to do multiple params on pocketic query_call

gm gm

This is a sample code of the test hello world in rust

#[test]
fn test_hello_world() {
    let (pic, backend_canister) = setup();

    let Ok(WasmResult::Reply(response)) = pic.query_call(
        backend_canister,
        Principal::anonymous(),
        "greet",
        encode_one("ICP").unwrap(),
    ) else {
        panic!("Expected reply");
    };
    let result: String = decode_one(&response).unwrap();
    assert_eq!(result, "Hello, ICP!");
}

This has an example for query_call of greet with 1 parameter “name”

My question is, how do we do multiple parameters?

Case in point: QR Code canister

canidid:

type Options = record {
  add_logo: bool;
  add_gradient: bool;
  add_transparency: opt bool;
};

type QrError = record {
  message: text;
};

type QrResult = variant {
  Image: blob;
  Err: QrError;
}

service : {
    "qrcode_query": (input: text, options: Options) -> (QrResult) query;
    "qrcode": (input: text, options: Options) -> (QrResult);
}

I want to call “qrcode” query.

Thanks in advance.

links:
hello world test: icp-hello-world-rust/src/icp_hello_world_rust_backend/tests/integration_tests.rs at main · dfinity/icp-hello-world-rust · GitHub
qrcode lib.rs: examples/rust/qrcode/src/qrcode_backend/src/lib.rs at master · dfinity/examples · GitHub

You could use the following to pass multiple arguments:

use candid::Encode;

pic.query_call(
        backend_canister,
        Principal::anonymous(),
        "greet",
        Encode!(..., ...).unwrap(),
    )

Hi i can pass multiple string like this, but how can i pass like this in particular?

input: text, options: Options

Please see candid above for reference thanks

You can pass any values in Encode!(...).unwrap, e.g., Encode!("my string".to_string(), Options {add_logo: true, add_gradient: false, add_transparency: None}).unwrap()

1 Like

Oh wow :exploding_head: ok ill try, thanks!

I tried, it failed.
PS: I tried both “ICP” and “ICP”.to_string()

I added a struct

struct Options {
    add_logo: bool,
    add_gradient: bool,
    add_transparency: bool,
}

here’s the code snippet:

let Ok(WasmResult::Reply(response)) = pic.query_call(
        backend_canister,
        Principal::anonymous(),
        "qrcode",
        Encode!(
            "ICP",
            Options {
                add_logo: true,
                add_gradient: true,
                add_transparency: false
            }
        )
        .unwrap(),
    ) else {
        panic!("Expected reply");
    };

cli error:

   Compiling qrcode_backend v1.1.0 (/home/eli/rust/qrcode)
error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> tests/integration_tests.rs:33:13
   |
32 | /         Encode!(
33 | |             "ICP",
   | |             ^^^^^ doesn't have a size known at compile-time
34 | |             Options {
35 | |                 add_logo: true,
...  |
38 | |             }
39 | |         )
   | |_________- required by a bound introduced by this call
   |
   = help: the trait `Sized` is not implemented for `str`
note: required by an implicit `Sized` bound in `IDLBuilder::arg`
  --> /home/eli/.cargo/registry/src/index.crates.io-6f17d22bba15001f/candid-0.10.10/src/ser.rs:32:20
   |
32 |     pub fn arg<'a, T: types::CandidType>(&'a mut self, value: &T) -> Result<&'a mut Self> {
   |                    ^ required by the implicit `Sized` requirement on this type parameter in `IDLBuilder::arg`

error[E0308]: mismatched types
  --> tests/integration_tests.rs:34:13
   |
32 | /          Encode!(
33 | |              "ICP",
34 | |/             Options {
35 | ||                 add_logo: true,
36 | ||                 add_gradient: true,
37 | ||                 add_transparency: false
38 | ||             }
   | ||_____________^ expected `&_`, found `Options`
39 | |          )
   | |__________- arguments to this method are incorrect
   |
   = note: expected reference `&_`
                 found struct `Options`
note: method defined here
  --> /home/eli/.cargo/registry/src/index.crates.io-6f17d22bba15001f/candid-0.10.10/src/ser.rs:32:12
   |
32 |     pub fn arg<'a, T: types::CandidType>(&'a mut self, value: &T) -> Result<&'a mut Self> {
   |            ^^^
help: consider borrowing here
   |
34 |             &Options {
   |             +

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `qrcode_backend` (test "integration_tests") due to 2 previous errors

here’s my full code for your review:

use candid::{decode_one, CandidType, Encode, Principal};
use pocket_ic::{PocketIc, WasmResult};
use serde::Deserialize;
use std::fs;

#[derive(CandidType, Deserialize)]
struct Options {
    add_logo: bool,
    add_gradient: bool,
    add_transparency: Option<bool>,
}

#[derive(CandidType, Deserialize)]
struct QrError {
    message: String,
}

#[derive(CandidType, Deserialize)]
enum QrResult {
    Image(Vec<u8>),
    Err(QrError),
}

const BACKEND_WASM: &str = "target/wasm32-unknown-unknown/release/qrcode_backend.wasm";

fn setup() -> (PocketIc, Principal) {
    let pic = PocketIc::new();

    let backend_canister = pic.create_canister();
    pic.add_cycles(backend_canister, 2_000_000_000_000); // 2T Cycles
    let wasm = fs::read(BACKEND_WASM).expect("Wasm file not found, run 'dfx build'.");
    pic.install_canister(backend_canister, wasm, vec![], None);
    (pic, backend_canister)
}

#[test]
fn test_hello_world() {
    let (pic, backend_canister) = setup();

    let Ok(WasmResult::Reply(response)) = pic.query_call(
        backend_canister,
        Principal::anonymous(),
        "qrcode",
        Encode!(
            &"https://facebook.com/".to_string(),
            &Options {
                add_logo: true,
                add_gradient: true,
                add_transparency: Some(false),
            }
        )
        .unwrap(),
    ) else {
        panic!("Query call failed")
    };
    let result: QrResult = decode_one(&response).unwrap();
    assert!(matches!(result, QrResult::Image(_)));
}

As the error suggests, you need to pass references, i.e., prefix the two args with &.

I was able to do multiple params now thanks to Encode!() and reference &var. Thanks @mraszyk