Repository: cobalt-org/liquid-rust
Pull request #349 (2019-08-29 11:34:35)

Feature/where filter 291
- [x] Tests created for any new feature or regression tests for bugfixes.
- [x] Run rustfmt on my code
- [x] Run clippy on my code



Patch:
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 1628445..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,80 +0,0 @@
-sudo: false
-language: rust
-rust:
-- 1.31.0  # Oldest supported version
-- stable
-- beta
-- nightly
-matrix:
-  include:
-  - env: RUSTFMT
-    rust: 1.31.0  # `stable`: Locking down for consistent behavior
-    install:
-      - rustup component add rustfmt
-    script:
-      - cargo fmt -- --check
-  - env: RUSTFLAGS="-D warnings"
-    rust: 1.31.0  # `stable`: Locking down for consistent behavior
-    install:
-    script:
-    - cargo check --tests
-  - env: CLIPPY
-    rust: 1.31.0  # `stable`: Locking down for consistent behavior
-    install:
-      - rustup component add clippy
-    script:
-      - cargo clippy --all-features
-
-env:
-  global:
-  - COVERALLS=0.0.6
-  - WHEN=0.1.0
-  - secure: FGosPYxgSM1Csyy2q/OiSW2KA7IDlIlLTODxwgszP/MIwOIMobAs5f+IqrEngEi3zKa0IPahQ3DZMZFAaNw9e1gI90ZQKpYgDQHNPeCtO0q4OV94RAjAFqhqVPxXwmNug88tm3NMokzzOafosWD8AzL7dYAx63KBpgCNZteW6CM=
-
-install:
-- rustc -Vv
-- cargo -V
-- which cargo-coveralls || travis_wait cargo install cargo-travis --force --vers $COVERALLS
-- if [[ `cargo-when --version` != *$WHEN ]] ; then travis_wait cargo install cargo-when --force --vers $WHEN; fi
-- export PATH=$HOME/.cargo/bin:$PATH
-
-script:
-- cargo check --verbose --all
-- cargo check --verbose --features "cli serde_json object_sorted"
-- cargo test  --verbose --all
-- cargo when --channel nightly bench --all
-- cargo when --channel stable doc --all --no-deps --all-features
-
-after_success:
-- cargo when --channel stable coveralls
-
-branches:
-  only:
-  # Release tags
-  - /^v\d+\.\d+\.\d+.*$/
-  - master
-
-addons:
-  apt:
-    packages:
-    # necessary for `cargo coveralls`
-    - libcurl4-openssl-dev
-    - libelf-dev
-    - libdw-dev
-    - binutils-dev
-    - cmake
-
-# Need to cache the whole `.cargo` directory to keep .crates.toml for
-# cargo-update to work
-cache:
-  directories:
-    - /home/travis/.cargo
-# But don't cache the cargo registry
-before_cache:
-- rm -rf $HOME/.cargo/registry
-# Travis can't cache files that are not readable by "others"
-- chmod -R a+r $HOME/.cargo
-
-notifications:
-  email:
-    on_success: never
diff --git a/Cargo.toml b/Cargo.toml
index 480d58f..53330dd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,8 +14,7 @@ keywords = ["liquid", "template", "templating", "language", "html"]
 license = "MIT"
 
 [badges]
-travis-ci = { repository = "cobalt-org/liquid-rust" }
-appveyor  = { repository = "johannhof/liquid-rust" }
+azure-devops = { project = "cobalt-org", pipeline = "liquid-rust" }
 
 [[bin]]
 name = "liquid-dbg"
diff --git a/README.md b/README.md
index fb017ac..c299ec2 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,8 @@ liquid-rust
 
 > [Liquid templating](http://liquidmarkup.org/) for Rust
 
-[![Travis Status](https://travis-ci.org/cobalt-org/liquid-rust.svg?branch=master)](https://travis-ci.org/cobalt-org/liquid-rust)
-[![Appveyor Status](https://ci.appveyor.com/api/projects/status/n1nqaitd5uja8tsi/branch/master?svg=true)](https://ci.appveyor.com/project/johannhof/liquid-rust/branch/master)
+[![Build Status](https://dev.azure.com/cobalt-org/cobalt-org/_apis/build/status/liquid-rust?branchName=master)](https://dev.azure.com/cobalt-org/cobalt-org/_build/latest?definitionId=1&branchName=master)
 [![Crates Status](https://img.shields.io/crates/v/liquid.svg)](https://crates.io/crates/liquid)
-[![Coverage Status](https://coveralls.io/repos/github/cobalt-org/liquid-rust/badge.svg?branch=master)](https://coveralls.io/github/cobalt-org/liquid-rust?branch=master)
 [![Dependency Status](https://dependencyci.com/github/cobalt-org/liquid-rust/badge)](https://dependencyci.com/github/cobalt-org/liquid-rust)
 
 Goals:
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 9548f0c..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-environment:
-  global:
-    RUST_VERSION: stable
-    #APPVEYOR_CACHE_SKIP_RESTORE: true
-
-  matrix:
-  # Stable channel
-  - TARGET: i686-pc-windows-msvc
-    CHANNEL: stable
-  - TARGET: x86_64-pc-windows-msvc
-    CHANNEL: stable
-  # Beta channel
-  - TARGET: x86_64-pc-windows-msvc
-    CHANNEL: beta
-  # Nightly channel
-  - TARGET: x86_64-pc-windows-msvc
-    CHANNEL: nightly
-
-install:
-- ps: >-
-    $Env:PATH += ';C:\msys64\usr\bin'
-- curl -sSf -o rustup-init.exe https://win.rustup.rs/
-- rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION%
-- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
-- rustc -Vv
-- cargo -V
-
-test_script:
-- cargo check --verbose --all
-- cargo check --verbose --features "cli serde_json object_sorted"
-- del target\debug\deps\*liquid*  # Avoid skeptic problems
-- cargo test  --verbose --all
-
-branches:
-  only:
-  # Release tags
-  - /^v\d+\.\d+\.\d+.*$/
-  - master
-
-cache:
-- C:\Users\appveyor\.cargo\registry
-
-notifications:
-- provider: Email
-  on_build_success: false
-
-# Building is done in the test phase, so we disable Appveyor's build phase.
-build: false
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 369d500..8b86be2 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -9,7 +9,9 @@ stages:
 - template: azure/stages.yml@templates
   parameters:
     minrust: 1.34.0
-    codecov_token: $(CODECOV_TOKEN_SECRET)
+    # Crashes for some reason. Note: does not run in PRs, so needs to be tested
+    # in `master`.
+    #codecov_token: $(CODECOV_TOKEN_SECRET)
 - stage: committed
   displayName: Lint History
   dependsOn: []
diff --git a/liquid-compiler/Cargo.toml b/liquid-compiler/Cargo.toml
index 3ef1435..8f8baba 100644
--- a/liquid-compiler/Cargo.toml
+++ b/liquid-compiler/Cargo.toml
@@ -11,8 +11,7 @@ keywords = ["liquid", "template", "templating", "language", "html"]
 license = "MIT"
 
 [badges]
-travis-ci = { repository = "cobalt-org/liquid-rust" }
-appveyor  = { repository = "johannhof/liquid-rust" }
+azure-devops = { project = "cobalt-org", pipeline = "liquid-rust" }
 
 [dependencies]
 itertools = "0.8.0"
diff --git a/liquid-compiler/README.md b/liquid-compiler/README.md
index 004aadc..7027002 100644
--- a/liquid-compiler/README.md
+++ b/liquid-compiler/README.md
@@ -3,10 +3,8 @@ liquid-compiler
 
 > [Liquid templating](http://liquidmarkup.org/) for Rust
 
-[![Travis Status](https://travis-ci.org/cobalt-org/liquid-rust.svg?branch=master)](https://travis-ci.org/cobalt-org/liquid-rust)
-[![Appveyor Status](https://ci.appveyor.com/api/projects/status/n1nqaitd5uja8tsi/branch/master?svg=true)](https://ci.appveyor.com/project/johannhof/liquid-rust/branch/master)
+[![Build Status](https://dev.azure.com/cobalt-org/cobalt-org/_apis/build/status/liquid-rust?branchName=master)](https://dev.azure.com/cobalt-org/cobalt-org/_build/latest?definitionId=1&branchName=master)
 [![Crates Status](https://img.shields.io/crates/v/liquid.svg)](https://crates.io/crates/liquid)
-[![Coverage Status](https://coveralls.io/repos/github/cobalt-org/liquid-rust/badge.svg?branch=master)](https://coveralls.io/github/cobalt-org/liquid-rust?branch=master)
 [![Dependency Status](https://dependencyci.com/github/cobalt-org/liquid-rust/badge)](https://dependencyci.com/github/cobalt-org/liquid-rust)
 
 Usage
diff --git a/liquid-derive/Cargo.toml b/liquid-derive/Cargo.toml
index c7de7cb..1c685d0 100644
--- a/liquid-derive/Cargo.toml
+++ b/liquid-derive/Cargo.toml
@@ -12,8 +12,7 @@ license = "MIT"
 proc-macro = true
 
 [badges]
-travis-ci = { repository = "cobalt-org/liquid-rust" }
-appveyor  = { repository = "johannhof/liquid-rust" }
+azure-devops = { project = "cobalt-org", pipeline = "liquid-rust" }
 
 [dependencies]
 syn = "0.15"
diff --git a/liquid-derive/README.md b/liquid-derive/README.md
index feb7fe5..de9aded 100644
--- a/liquid-derive/README.md
+++ b/liquid-derive/README.md
@@ -3,10 +3,8 @@ liquid-derive
 
 > [Liquid templating](http://liquidmarkup.org/) for Rust
 
-[![Travis Status](https://travis-ci.org/cobalt-org/liquid-rust.svg?branch=master)](https://travis-ci.org/cobalt-org/liquid-rust)
-[![Appveyor Status](https://ci.appveyor.com/api/projects/status/n1nqaitd5uja8tsi/branch/master?svg=true)](https://ci.appveyor.com/project/johannhof/liquid-rust/branch/master)
+[![Build Status](https://dev.azure.com/cobalt-org/cobalt-org/_apis/build/status/liquid-rust?branchName=master)](https://dev.azure.com/cobalt-org/cobalt-org/_build/latest?definitionId=1&branchName=master)
 [![Crates Status](https://img.shields.io/crates/v/liquid.svg)](https://crates.io/crates/liquid)
-[![Coverage Status](https://coveralls.io/repos/github/cobalt-org/liquid-rust/badge.svg?branch=master)](https://coveralls.io/github/cobalt-org/liquid-rust?branch=master)
 [![Dependency Status](https://dependencyci.com/github/cobalt-org/liquid-rust/badge)](https://dependencyci.com/github/cobalt-org/liquid-rust)
 
 Usage
diff --git a/liquid-error/Cargo.toml b/liquid-error/Cargo.toml
index 35af1ce..2efc63b 100644
--- a/liquid-error/Cargo.toml
+++ b/liquid-error/Cargo.toml
@@ -11,7 +11,6 @@ keywords = ["liquid", "template", "templating", "language", "html"]
 license = "MIT"
 
 [badges]
-travis-ci = { repository = "cobalt-org/liquid-rust" }
-appveyor  = { repository = "johannhof/liquid-rust" }
+azure-devops = { project = "cobalt-org", pipeline = "liquid-rust" }
 
 [dependencies]
diff --git a/liquid-error/README.md b/liquid-error/README.md
index 9c05719..a69b486 100644
--- a/liquid-error/README.md
+++ b/liquid-error/README.md
@@ -3,10 +3,8 @@ liquid-error
 
 > [Liquid templating](http://liquidmarkup.org/) for Rust
 
-[![Travis Status](https://travis-ci.org/cobalt-org/liquid-rust.svg?branch=master)](https://travis-ci.org/cobalt-org/liquid-rust)
-[![Appveyor Status](https://ci.appveyor.com/api/projects/status/n1nqaitd5uja8tsi/branch/master?svg=true)](https://ci.appveyor.com/project/johannhof/liquid-rust/branch/master)
+[![Build Status](https://dev.azure.com/cobalt-org/cobalt-org/_apis/build/status/liquid-rust?branchName=master)](https://dev.azure.com/cobalt-org/cobalt-org/_build/latest?definitionId=1&branchName=master)
 [![Crates Status](https://img.shields.io/crates/v/liquid.svg)](https://crates.io/crates/liquid)
-[![Coverage Status](https://coveralls.io/repos/github/cobalt-org/liquid-rust/badge.svg?branch=master)](https://coveralls.io/github/cobalt-org/liquid-rust?branch=master)
 [![Dependency Status](https://dependencyci.com/github/cobalt-org/liquid-rust/badge)](https://dependencyci.com/github/cobalt-org/liquid-rust)
 
 Usage
diff --git a/liquid-interpreter/Cargo.toml b/liquid-interpreter/Cargo.toml
index 1be534b..726b3b1 100644
--- a/liquid-interpreter/Cargo.toml
+++ b/liquid-interpreter/Cargo.toml
@@ -11,8 +11,7 @@ keywords = ["liquid", "template", "templating", "language", "html"]
 license = "MIT"
 
 [badges]
-travis-ci = { repository = "cobalt-org/liquid-rust" }
-appveyor  = { repository = "johannhof/liquid-rust" }
+azure-devops = { project = "cobalt-org", pipeline = "liquid-rust" }
 
 [dependencies]
 itertools = "0.8.0"
diff --git a/liquid-interpreter/README.md b/liquid-interpreter/README.md
index f75668e..d780606 100644
--- a/liquid-interpreter/README.md
+++ b/liquid-interpreter/README.md
@@ -3,10 +3,8 @@ liquid-interpreter
 
 > [Liquid templating](http://liquidmarkup.org/) for Rust
 
-[![Travis Status](https://travis-ci.org/cobalt-org/liquid-rust.svg?branch=master)](https://travis-ci.org/cobalt-org/liquid-rust)
-[![Appveyor Status](https://ci.appveyor.com/api/projects/status/n1nqaitd5uja8tsi/branch/master?svg=true)](https://ci.appveyor.com/project/johannhof/liquid-rust/branch/master)
+[![Build Status](https://dev.azure.com/cobalt-org/cobalt-org/_apis/build/status/liquid-rust?branchName=master)](https://dev.azure.com/cobalt-org/cobalt-org/_build/latest?definitionId=1&branchName=master)
 [![Crates Status](https://img.shields.io/crates/v/liquid.svg)](https://crates.io/crates/liquid)
-[![Coverage Status](https://coveralls.io/repos/github/cobalt-org/liquid-rust/badge.svg?branch=master)](https://coveralls.io/github/cobalt-org/liquid-rust?branch=master)
 [![Dependency Status](https://dependencyci.com/github/cobalt-org/liquid-rust/badge)](https://dependencyci.com/github/cobalt-org/liquid-rust)
 
 Usage
diff --git a/liquid-value/Cargo.toml b/liquid-value/Cargo.toml
index 50cbe36..37b5dd6 100644
--- a/liquid-value/Cargo.toml
+++ b/liquid-value/Cargo.toml
@@ -11,8 +11,7 @@ keywords = ["liquid", "template", "templating", "language", "html"]
 license = "MIT"
 
 [badges]
-travis-ci = { repository = "cobalt-org/liquid-rust" }
-appveyor  = { repository = "johannhof/liquid-rust" }
+azure-devops = { project = "cobalt-org", pipeline = "liquid-rust" }
 
 [dependencies]
 itertools = "0.8.0"
diff --git a/liquid-value/README.md b/liquid-value/README.md
index 8a3d3a7..3e0dabe 100644
--- a/liquid-value/README.md
+++ b/liquid-value/README.md
@@ -3,10 +3,8 @@ liquid-value
 
 > [Liquid templating](http://liquidmarkup.org/) for Rust
 
-[![Travis Status](https://travis-ci.org/cobalt-org/liquid-rust.svg?branch=master)](https://travis-ci.org/cobalt-org/liquid-rust)
-[![Appveyor Status](https://ci.appveyor.com/api/projects/status/n1nqaitd5uja8tsi/branch/master?svg=true)](https://ci.appveyor.com/project/johannhof/liquid-rust/branch/master)
+[![Build Status](https://dev.azure.com/cobalt-org/cobalt-org/_apis/build/status/liquid-rust?branchName=master)](https://dev.azure.com/cobalt-org/cobalt-org/_build/latest?definitionId=1&branchName=master)
 [![Crates Status](https://img.shields.io/crates/v/liquid.svg)](https://crates.io/crates/liquid)
-[![Coverage Status](https://coveralls.io/repos/github/cobalt-org/liquid-rust/badge.svg?branch=master)](https://coveralls.io/github/cobalt-org/liquid-rust?branch=master)
 [![Dependency Status](https://dependencyci.com/github/cobalt-org/liquid-rust/badge)](https://dependencyci.com/github/cobalt-org/liquid-rust)
 
 Usage
diff --git a/src/filters/std/array.rs b/src/filters/std/array.rs
index f82914a..34c9daa 100644
--- a/src/filters/std/array.rs
+++ b/src/filters/std/array.rs
@@ -4,7 +4,7 @@ use liquid_derive::*;
 use liquid_error::Result;
 use liquid_interpreter::Context;
 use liquid_interpreter::Expression;
-use liquid_value::{Scalar, Value};
+use liquid_value::{Object, Scalar, Value};
 use std::cmp;
 
 #[derive(Debug, FilterParameters)]
@@ -101,6 +101,87 @@ impl Filter for SortNaturalFilter {
     }
 }
 
+#[derive(Debug, FilterParameters)]
+struct WhereArgs {
+    #[parameter(description = "The property being matched", arg_type = "str")]
+    property: Expression,
+    #[parameter(
+        description = "The value the property is matched with",
+        arg_type = "any"
+    )]
+    target_value: Option<Expression>,
+}
+
+#[derive(Clone, ParseFilter, FilterReflection)]
+#[filter(
+    name = "where",
+    description = "Filter the elements of an array to those with a certain property value. \
+                   By default the target is any truthy value.",
+    parameters(WhereArgs),
+    parsed(WhereFilter)
+)]
+pub struct Where;
+
+#[derive(Debug, FromFilterParameters, Display_filter)]
+#[name = "where"]
+struct WhereFilter {
+    #[parameters]
+    args: WhereArgs,
+}
+
+fn apply_where_filter<'a, T: Iterator<Item = &'a Object>>(
+    input: T,
+    property: &str,
+    target_value: Option<&Value>,
+) -> Vec<Value> {
+    match target_value {
+        None => input
+            .filter(|object| object.get(property).map_or(false, Value::is_truthy))
+            .map(|object| Value::Object(object.clone()))
+            .collect(),
+        Some(target_value) => input
+            .filter(|object| {
+                object
+                    .get(property)
+                    .map_or(false, |value| value == target_value)
+            })
+            .map(|object| Value::Object(object.clone()))
+            .collect(),
+    }
+}
+
+impl Filter for WhereFilter {
+    fn evaluate(&self, input: &Value, context: &Context) -> Result<Value> {
+        let args = self.args.evaluate(context)?;
+
+        match input {
+            Value::Array(array) => {
+                if array.is_empty() {
+                    // Retrun an empty array only if we got an empty array
+                    return Ok(Value::array(vec![]));
+                }
+                if !array.iter().all(Value::is_object) {
+                    return Ok(Value::Nil);
+                }
+                Ok(Value::array(apply_where_filter(
+                    array.iter().filter_map(Value::as_object),
+                    &args.property,
+                    args.target_value,
+                )))
+            }
+            // In the case of a single object, take it, but return an array.
+            Value::Object(object) => Ok(Value::array(apply_where_filter(
+                std::iter::once(object),
+                &args.property,
+                args.target_value,
+            ))),
+            _ => Err(invalid_input(
+                "Array of objects or a single object expected",
+            )),
+        }
+    }
+}
+
 /// Removes any duplicate elements in an array.
 ///
 /// This has an O(n^2) worst-case complexity.
diff --git a/src/filters/std/mod.rs b/src/filters/std/mod.rs
index d6fba8c..d67bfac 100644
--- a/src/filters/std/mod.rs
+++ b/src/filters/std/mod.rs
@@ -13,7 +13,9 @@ mod slice;
 mod string;
 mod url;
 
-pub use self::array::{Compact, Concat, First, Join, Last, Map, Reverse, Sort, SortNatural, Uniq};
+pub use self::array::{
+    Compact, Concat, First, Join, Last, Map, Reverse, Sort, SortNatural, Uniq, Where,
+};
 pub use self::date::Date;
 pub use self::html::{Escape, EscapeOnce, NewlineToBr, StripHtml};
 pub use self::math::{


Test patch:
diff --git a/tests/conformance_ruby/standard_filter_test.rs b/tests/conformance_ruby/standard_filter_test.rs
index 3dc74dc..098f832 100644
--- a/tests/conformance_ruby/standard_filter_test.rs
+++ b/tests/conformance_ruby/standard_filter_test.rs
@@ -865,10 +865,7 @@ fn test_date_raises_nothing() {
 }
 
 #[test]
-#[should_panic] // liquid-rust#291
 fn test_where() {
-    panic!("where is unimplemented");
-    /*
     let input = v!([
       { "handle": "alpha", "ok": true },
       { "handle": "beta", "ok": false },
@@ -881,92 +878,85 @@ fn test_where() {
       { "handle": "delta", "ok": true }
     ]);
 
-    assert_eq!(expectation, filters!(where, input, v!("ok"), true));
-    assert_eq!(expectation, filters!(where, input, v!("ok")));
-    */
+    assert_eq!(expectation, filters!(Where, input, v!("ok"), v!(true)));
+    assert_eq!(expectation, filters!(Where, input, v!("ok")));
 }
 
 #[test]
-#[should_panic] // liquid-rust#291
 fn test_where_no_key_set() {
-    panic!("where is unimplemented");
-    /*
-    input = [
-      { v!("handle"): v!("alpha"), v!("ok"): true },
-      { v!("handle"): v!("beta") },
-      { v!("handle"): v!("gamma") },
-      { v!("handle"): v!("delta"), v!("ok"): true }
-    ]
-
-    expectation = [
-      { v!("handle"): v!("alpha"), v!("ok"): true },
-      { v!("handle"): v!("delta"), v!("ok"): true }
-    ]
-
-    assert_eq!(expectation, filters!(where, input, v!("ok"), true));
-    assert_eq!(expectation, filters!(where, input, v!("ok")));
-    */
+    let input = v!([
+      { "handle": "alpha", "ok": true },
+      { "handle": "beta" },
+      { "handle": "gamma" },
+      { "handle": "delta", "ok": true }
+    ]);
+
+    let expectation = v!([
+      { "handle": "alpha", "ok": true },
+      { "handle": "delta", "ok": true }
+    ]);
+
+    assert_eq!(expectation, filters!(Where, input, v!("ok"), v!(true)));
+    assert_eq!(expectation, filters!(Where, input, v!("ok")));
 }
 
 #[test]
-#[should_panic] // liquid-rust#291
 fn test_where_non_array_map_input() {
-    panic!("where is unimplemented");
-    /*
-    assert_eq!([{ v!("a"): v!("ok") }], filters!(where, { v!("a"): v!("ok") }, "a", r#"ok")#);
-    assert_eq!([], filters!(where, { v!("a"): v!("not ok") }, "a", r#"ok")#);
-    */
+    assert_eq!(
+        v!([{ "a": "ok" }]),
+        filters!(Where, v!({ "a": "ok" }), v!("a"), v!("ok"))
+    );
+    assert_eq!(
+        v!([]),
+        filters!(Where, v!({ "a": "not ok" }), v!("a"), v!("ok"))
+    );
 }
 
 #[test]
-#[should_panic] // liquid-rust#291
 fn test_where_indexable_but_non_map_value() {
-    panic!("where is unimplemented");
-    /*
-    assert_raises(Liquid::ArgumentError) { filters!(where, 1, v!("ok"), true) }
-    assert_raises(Liquid::ArgumentError) { filters!(where, 1, v!("ok")) }
-    */
+    filters_fail!(Where, v!(1), v!("ok"), v!(true));
+    filters_fail!(Where, v!(1), v!("ok"));
 }
 
 #[test]
-#[should_panic] // liquid-rust#291
 fn test_where_non_boolean_value() {
-    panic!("where is unimplemented");
-    /*
-    input = [
-      { v!("message"): v!("Bonjour!"), v!("language"): v!("French") },
-      { v!("message"): v!("Hello!"), v!("language"): v!("English") },
-      { v!("message"): v!("Hallo!"), v!("language"): v!("German") }
-    ]
-
-    assert_eq!([{ v!("message"): v!("Bonjour!"), v!("language"): v!("French") }], filters!(where, input, "language", r#"French")#);
-    assert_eq!([{ v!("message"): v!("Hallo!"), v!("language"): v!("German") }], filters!(where, input, "language", r#"German")#);
-    assert_eq!([{ v!("message"): v!("Hello!"), v!("language"): v!("English") }], filters!(where, input, "language", r#"English")#);
-    */
+    let input = v!([
+      { "message": "Bonjour!", "language": "French" },
+      { "message": "Hello!", "language": "English" },
+      { "message": "Hallo!", "language": "German" }
+    ]);
+
+    assert_eq!(
+        v!([{ "message": "Bonjour!", "language": "French" }]),
+        filters!(Where, input, v!("language"), v!("French"))
+    );
+    assert_eq!(
+        v!([{ "message": "Hallo!", "language": "German" }]),
+        filters!(Where, input, v!("language"), v!("German"))
+    );
+    assert_eq!(
+        v!([{ "message": "Hello!", "language": "English" }]),
+        filters!(Where, input, v!("language"), v!("English"))
+    );
 }
 
 #[test]
-#[should_panic] // liquid-rust#291
 fn test_where_array_of_only_unindexable_values() {
-    panic!("where is unimplemented");
-    /*
-    assert_eq!(Nil, filters!(where, [Nil], v!("ok"), true));
-    assert_eq!(Nil, filters!(where, [Nil], v!("ok")));
-    */
+    assert_eq!(Nil, filters!(Where, v!([Nil]), v!("ok"), v!(true)));
+    assert_eq!(Nil, filters!(Where, v!([Nil]), v!("ok")));
 }
 
 #[test]
-#[should_panic] // liquid-rust#291
 fn test_where_no_target_value() {
-    panic!("where is unimplemented");
-    /*
-    input = [
-      { v!("foo"): false },
-      { v!("foo"): true },
-      { v!("foo"): v!("for sure") },
-      { v!("bar"): true }
-    ]
-
-    assert_eq!([{ v!("foo"): true }, { v!("foo"): v!("for sure") }], filters!(where, input, v!("foo")));
-    */
+    let input = v!([
+      { "foo": false },
+      { "foo": true },
+      { "foo": "for sure" },
+      { "bar": true }
+    ]);
+
+    assert_eq!(
+        v!([{ "foo": true }, { "foo": "for sure" }]),
+        filters!(Where, input, v!("foo"))
+    );
 }