Skip to content

Commit

Permalink
Merge pull request #3 from desmos-labs/filter-posts-fixes
Browse files Browse the repository at this point in the history
Filter posts fixes
  • Loading branch information
leobragaz authored Mar 17, 2021
2 parents fa61cbe + c29f8ef commit 1d4e1bc
Show file tree
Hide file tree
Showing 23 changed files with 378 additions and 382 deletions.
36 changes: 2 additions & 34 deletions Developing.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
# Developing

If you have recently created a contract with this template, you probably could use some
help on how to build and test the contract, as well as prepare it for production. This
file attempts to provide a brief overview, assuming you have installed a recent
version of Rust already (eg. 1.44.1+).

## Prerequisites

Before starting, make sure you have [rustup](https://rustup.rs/) along with a
recent `rustc` and `cargo` version installed. Currently, we are testing on 1.44.1+.
recent `rustc` and `cargo` version installed. Currently, we are testing on `1.48`.

And you need to have the `wasm32-unknown-unknown` target installed as well.

Expand All @@ -22,36 +15,11 @@ rustup target list --installed
rustup target add wasm32-unknown-unknown
```

## Compiling and running tests

Now that you created your custom contract, make sure you can compile and run it before
making any changes. Go into the repository and do:

```sh
# this will produce a wasm build in ./target/wasm32-unknown-unknown/release/YOUR_NAME_HERE.wasm
cargo wasm

# this runs unit tests with helpful backtraces
RUST_BACKTRACE=1 cargo unit-test

# auto-generate json schema
cargo schema
```

### Understanding the tests

The main code is in `src/contract.rs` and the unit tests there run in pure rust,
which makes them very quick to execute and give nice output on failures, especially
if you do `RUST_BACKTRACE=1 cargo unit-test`.

We consider testing critical for anything on a blockchain, and recommend to always keep
the tests up to date.

## Generating JSON Schema

While the Wasm calls (`init`, `handle`, `query`) accept JSON, this is not enough
information to use it. We need to expose the schema for the expected messages to the
clients. You can generate this schema by calling `cargo schema`, which will output
clients. You can generate this schema by calling `cargo schema` (from within a contract's folder), which will output
4 files in `./schema`, corresponding to the 3 message types the contract accepts,
as well as the internal `State`.

Expand Down
62 changes: 0 additions & 62 deletions Importing.md

This file was deleted.

2 changes: 1 addition & 1 deletion contracts/filter-posts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "filter-posts"
version = "0.1.0"
authors = ["bragaz <[email protected]>"]
edition = "2018"
description = "Implements posts' filtering by checking the posts' reports amount"
description = "A cosmwasm contract that filters desmos' network posts based on the number of reports a post has"
license = "Apache 2.0"
repository = "https://github.com/desmos-labs/desmos-contracts"

Expand Down
9 changes: 5 additions & 4 deletions contracts/filter-posts/examples/schema.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::env::current_dir;
use std::fs::create_dir_all;
use std::{env::current_dir, fs::create_dir_all};

use cosmwasm_schema::{export_schema, remove_schemas, schema_for};

use filter_posts::msg::{HandleMsg, InitMsg, QueryMsg};
use filter_posts::state::State;
use filter_posts::{
msg::{HandleMsg, InitMsg, QueryMsg},
state::State,
};

fn main() {
let mut out_dir = current_dir().unwrap();
Expand Down
163 changes: 157 additions & 6 deletions contracts/filter-posts/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use crate::{
error::ContractError,
msg::{HandleMsg, InitMsg, QueryMsg},
state::{state_read, state_store, State},
};
use cosmwasm_std::{
attr, to_binary, Binary, Deps, DepsMut, Env, HandleResponse, InitResponse, MessageInfo,
StdResult,
};

use crate::error::ContractError;
use crate::msg::{HandleMsg, InitMsg, QueryMsg};
use crate::state::{state_read, state_store, State};
use desmos::custom_query::{query_post_reports, query_posts, PostsResponse};
use desmos::types::Post;
use desmos::{
custom_query::{query_post_reports, query_posts},
query_types::PostsResponse,
types::Post,
};

// Note, you can use StdResult in some functions where you do not
// make use of the custom errors
Expand Down Expand Up @@ -76,6 +80,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
pub fn is_under_reports_limit(deps: Deps, post: &Post, reports_limit: u16) -> bool {
let reports_len = query_post_reports(&deps.querier, post.post_id.clone())
.unwrap()
.reports
.len() as u16;
reports_len < reports_limit
}
Expand All @@ -84,10 +89,156 @@ pub fn is_under_reports_limit(deps: Deps, post: &Post, reports_limit: u16) -> bo
pub fn query_filtered_posts(deps: Deps, reports_limit: u16) -> StdResult<PostsResponse> {
let posts = query_posts(&deps.querier)?;
let filtered_posts = posts
.posts
.into_iter()
.filter(|post| is_under_reports_limit(deps, post, reports_limit))
.collect::<Vec<Post>>();
Ok(PostsResponse {
posts: filtered_posts,
})
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
contract::{handle, init, is_under_reports_limit, query_filtered_posts},
mock::mock_dependencies_with_custom_querier,
msg::{HandleMsg, InitMsg},
};
use cosmwasm_std::{
testing::{mock_env, mock_info},
HumanAddr,
};
use desmos::types::PollData;

fn setup_test(deps: DepsMut, env: Env, info: MessageInfo, default_reports_limit: u16) {
let init_msg = InitMsg {
reports_limit: default_reports_limit,
};
init(deps, env, info, init_msg).unwrap();
}

#[test]
fn test_init() {
let mut deps = mock_dependencies_with_custom_querier(&[]);

let sender_addr = HumanAddr::from("addr0001");
let info = mock_info(&sender_addr, &[]);

let init_msg = InitMsg { reports_limit: 5 };

let res = init(deps.as_mut(), mock_env(), info, init_msg).unwrap();
assert_eq!(0, res.messages.len());

let exp_log = vec![attr("action", "set_default_reports_limit")];

assert_eq!(res.attributes, exp_log);

// make sure that the state is set
let state = state_read(&deps.storage).load().unwrap();
assert_eq!(5, state.default_reports_limit)
}

#[test]
fn test_handle() {
let mut deps = mock_dependencies_with_custom_querier(&[]);
let editor_addr = HumanAddr::from("editor");
let info = mock_info(&editor_addr, &[]);
setup_test(deps.as_mut(), mock_env(), info.clone(), 3);

let exp_res = HandleResponse {
messages: vec![],
attributes: vec![
attr("action", "edit_reports_limit"),
attr("editor", info.sender.clone()),
],
data: None,
};

let msg = HandleMsg::EditReportsLimit { reports_limit: 5 };
let res = handle(deps.as_mut(), mock_env(), info.clone(), msg.clone());

// assert it not fails
assert!(res.is_ok());

assert_eq!(res.unwrap(), exp_res);

let res = handle(deps.as_mut(), mock_env(), info.clone(), msg.clone());
match res.unwrap_err() {
ContractError::EqualsReportLimits { .. } => {}
_ => panic!("expected unregistered error"),
}
}

#[test]
fn is_under_reports_limit_checks_correctly() {
let deps = mock_dependencies_with_custom_querier(&[]);
let post = Post {
post_id: "id123".to_string(),
parent_id: Some("id345".to_string()),
message: "message".to_string(),
created: "date-time".to_string(),
last_edited: "date-time".to_string(),
allows_comments: false,
subspace: "subspace".to_string(),
optional_data: Some(vec![]),
attachments: Some(vec![]),
poll_data: Some(PollData {
question: "".to_string(),
provided_answers: vec![],
end_date: "".to_string(),
allows_multiple_answers: false,
allows_answer_edits: false,
}),
creator: "default_creator".to_string(),
};

// post is under the report limit
let res = is_under_reports_limit(deps.as_ref(), &post, 5);
assert_eq!(res, true);

// post is over the report limit
let res = is_under_reports_limit(deps.as_ref(), &post, 1);
assert_eq!(res, false)
}

#[test]
fn query_filtered_posts_filter_correctly() {
let mut deps = mock_dependencies_with_custom_querier(&[]);
let sender_addr = HumanAddr::from("addr0001");
let info = mock_info(&sender_addr, &[]);

setup_test(deps.as_mut(), mock_env(), info, 5);

let post = Post {
post_id: "id123".to_string(),
parent_id: Some("id345".to_string()),
message: "message".to_string(),
created: "date-time".to_string(),
last_edited: "date-time".to_string(),
allows_comments: false,
subspace: "subspace".to_string(),
optional_data: Some(vec![]),
attachments: Some(vec![]),
poll_data: Some(PollData {
question: "".to_string(),
provided_answers: vec![],
end_date: "".to_string(),
allows_multiple_answers: false,
allows_answer_edits: false,
}),
creator: "default_creator".to_string(),
};

let expected = PostsResponse { posts: vec![post] };

// post has less reports than the limit
let res = query_filtered_posts(deps.as_ref(), 3).unwrap();
assert_eq!(res, expected);

// post has equal reports to the limit
let res = query_filtered_posts(deps.as_ref(), 1).unwrap();
assert_eq!(res, PostsResponse { posts: vec![] })
}
}
Loading

0 comments on commit 1d4e1bc

Please sign in to comment.