Repository: mitsuhiko/minijinja (language: rust)

Issue:
`is none` and `is not none` throws exception
## Description

Error occurs with a simple `not none` check

```
Error: unknown test: test none is unknown (in template.html:1)
-------------------------------- template.html --------------------------------
   1 > {% if text is defined and text is not none and text|length %}
     i                                       ^^^^ unknown test
```

## Reproduction steps

```django
{% if text is defined and text is not none and text|length %}
  {{text}}
{% else %}
  NONE
{% endif %}
```

data
```json
{
  "text": "hello"
}
```

Additional helpful information:

- you can reproduce it in the playground


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 33d51324..9083d500 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ All notable changes to MiniJinja are documented here.
 - Fixed recursion detection for macros.
 - Enforce a maximum size of 10000 items on the range output.
 - Added fuel tracking support.
+- Added `none` test. (#185)
 
 # 0.28.0
 
diff --git a/minijinja/src/defaults.rs b/minijinja/src/defaults.rs
index 39559122..a27c1002 100644
--- a/minijinja/src/defaults.rs
+++ b/minijinja/src/defaults.rs
@@ -101,6 +101,7 @@ pub(crate) fn get_builtin_tests() -> BTreeMap<Cow<'static, str>, BoxedTest> {
     let mut rv = BTreeMap::new();
     rv.insert("undefined".into(), BoxedTest::new(tests::is_undefined));
     rv.insert("defined".into(), BoxedTest::new(tests::is_defined));
+    rv.insert("none".into(), BoxedTest::new(tests::is_none));
     rv.insert("safe".into(), BoxedTest::new(tests::is_safe));
     rv.insert("escaped".into(), BoxedTest::new(tests::is_safe));
     #[cfg(feature = "builtins")]


Test patch:
diff --git a/minijinja/src/tests.rs b/minijinja/src/tests.rs
index faaf7232..1ea2891f 100644
--- a/minijinja/src/tests.rs
+++ b/minijinja/src/tests.rs
@@ -207,6 +207,11 @@ pub fn is_defined(v: Value) -> bool {
     !v.is_undefined()
 }
 
+/// Checks if a value is none.
+pub fn is_none(v: Value) -> bool {
+    v.is_none()
+}
+
 /// Checks if a value is safe.
 ///
 /// This filter is also registered with the `escaped` alias.
diff --git a/minijinja/tests/inputs/tests.txt b/minijinja/tests/inputs/tests.txt
index da327c4c..b92d81c9 100644
--- a/minijinja/tests/inputs/tests.txt
+++ b/minijinja/tests/inputs/tests.txt
@@ -18,6 +18,8 @@ undefined: {{ two is undefined }}
 defined: {{ two is defined }}
 undefined2: {{ ohwell is undefined }}
 defined2: {{ ohwell is defined }}
+none: {{ none is none }}
+not-none: {{ 42 is not none }}
 number-int: {{ two is number }}
 number-float: {{ two_dot_two is number }}
 not-seq: {{ two is sequence }}
diff --git a/minijinja/tests/snapshots/test_templates__vm@debug.txt.snap b/minijinja/tests/snapshots/test_templates__vm@debug.txt.snap
index 76903a1a..76c13eef 100644
--- a/minijinja/tests/snapshots/test_templates__vm@debug.txt.snap
+++ b/minijinja/tests/snapshots/test_templates__vm@debug.txt.snap
@@ -40,6 +40,7 @@ State {
             "escaped",
             "even",
             "mapping",
+            "none",
             "number",
             "odd",
             "safe",
diff --git a/minijinja/tests/snapshots/test_templates__vm@tests.txt.snap b/minijinja/tests/snapshots/test_templates__vm@tests.txt.snap
index 337b5d85..7a380c0e 100644
--- a/minijinja/tests/snapshots/test_templates__vm@tests.txt.snap
+++ b/minijinja/tests/snapshots/test_templates__vm@tests.txt.snap
@@ -1,6 +1,6 @@
 ---
 source: minijinja/tests/test_templates.rs
-description: "even: {{ two is even }}\nodd: {{ two is odd }}\nundefined: {{ two is undefined }}\ndefined: {{ two is defined }}\nundefined2: {{ ohwell is undefined }}\ndefined2: {{ ohwell is defined }}\nnumber-int: {{ two is number }}\nnumber-float: {{ two_dot_two is number }}\nnot-seq: {{ two is sequence }}\nseq: {{ seq is sequence }}\nnot-map: {{ two is mapping }}\nmap: {{ map is mapping }}\nstring: {{ string is string }}\nnot-string: {{ mapping is string }}\nstarts-with-a: {{ string is startingwith('a') }}\nends-with-ha: {{ string is endingwith('ha') }}\nnot-safe: {{ \"foo\" is safe }}\nsafe: {{ \"foo\"|escape is safe }}"
+description: "even: {{ two is even }}\nodd: {{ two is odd }}\nundefined: {{ two is undefined }}\ndefined: {{ two is defined }}\nundefined2: {{ ohwell is undefined }}\ndefined2: {{ ohwell is defined }}\nnone: {{ none is none }}\nnot-none: {{ 42 is not none }}\nnumber-int: {{ two is number }}\nnumber-float: {{ two_dot_two is number }}\nnot-seq: {{ two is sequence }}\nseq: {{ seq is sequence }}\nnot-map: {{ two is mapping }}\nmap: {{ map is mapping }}\nstring: {{ string is string }}\nnot-string: {{ mapping is string }}\nstarts-with-a: {{ string is startingwith('a') }}\nends-with-ha: {{ string is endingwith('ha') }}\nnot-safe: {{ \"foo\" is safe }}\nsafe: {{ \"foo\"|escape is safe }}"
 info:
   map:
     foo: bar
@@ -19,6 +19,8 @@ undefined: false
 defined: true
 undefined2: true
 defined2: false
+none: true
+not-none: true
 number-int: true
 number-float: true
 not-seq: false