Repository: cobalt-org/liquid-rust (rust)

Issue:
`divide_by` 0 should error
Example test:
```rust
    assert_render_error!("{{ 1.0 | divided_by: 0.0 | ceil }}");
```

Shopify:
```ruby
    assert_raises(Liquid::FloatDomainError) do
      assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | ceil }}"
    end
```

- [Rust implementation](https://github.com/cobalt-org/liquid-rust/blob/master/src/filters/math.rs)
- [Ruby implementation](https://github.com/Shopify/liquid/blob/master/lib/liquid/standardfilters.rb)
- [Relevant tests](https://github.com/cobalt-org/liquid-rust/search?q=liquid+251&unscoped_q=liquid+251)
  - Once this is working, ideally the test will start failing.  We would just need to remove the `#[should_panic]` on it
  - If the test doesn't start failing, please temporarily remove `#[should_panic]`, and find or create an issue for the new failure

Pull request description:
fix(std): Divide by zero should error, not panic
fixes #251

Patch:
diff --git a/crates/lib/src/stdlib/filters/math.rs b/crates/lib/src/stdlib/filters/math.rs
index 1f107f7..6044dc8 100644
--- a/crates/lib/src/stdlib/filters/math.rs
+++ b/crates/lib/src/stdlib/filters/math.rs
@@ -313,6 +313,16 @@ impl Filter for DividedByFilter {
             .as_scalar()
             .ok_or_else(|| invalid_argument("operand", "Number expected"))?;
 
+        if let Some(o) = operand.to_integer() {
+            if o == 0 {
+                return Err(invalid_argument("operand", "Can't divide by zero"));
+            }
+        } else if let Some(o) = operand.to_float() {
+            if o == 0.0 {
+                return Err(invalid_argument("operand", "Can't divide by zero"));
+            }
+        }
+
         let result = input
             .to_integer()
             .and_then(|i| operand.to_integer().map(|o| Value::scalar(i / o)))
@@ -362,6 +372,16 @@ impl Filter for ModuloFilter {
             .as_scalar()
             .ok_or_else(|| invalid_argument("operand", "Number expected"))?;
 
+        if let Some(o) = operand.to_integer() {
+            if o == 0 {
+                return Err(invalid_argument("operand", "Can't divide by zero"));
+            }
+        } else if let Some(o) = operand.to_float() {
+            if o == 0.0 {
+                return Err(invalid_argument("operand", "Can't divide by zero"));
+            }
+        }
+
         let result = input
             .to_integer()
             .and_then(|i| operand.to_integer().map(|o| Value::scalar(i % o)))


Test patch:
diff --git a/tests/conformance_ruby/standard_filter_test.rs b/tests/conformance_ruby/standard_filter_test.rs
index bf5e7ff..2fbc891 100644
--- a/tests/conformance_ruby/standard_filter_test.rs
+++ b/tests/conformance_ruby/standard_filter_test.rs
@@ -1059,7 +1059,6 @@ fn test_times() {
 }
 
 #[test]
-#[should_panic] // liquid-rust#251
 fn test_divided_by() {
     assert_template_result!("4", r#"{{ 12 | divided_by:3 }}"#);
     assert_template_result!("4", r#"{{ 14 | divided_by:3 }}"#);
@@ -1074,7 +1073,6 @@ fn test_divided_by() {
 }
 
 #[test]
-#[should_panic] // liquid-rust#251
 fn test_modulo() {
     assert_template_result!("1", r#"{{ 3 | modulo:2 }}"#);
     assert_render_error!("{{ 1 | modulo:0 }}");
@@ -1083,7 +1081,6 @@ fn test_modulo() {
 }
 
 #[test]
-#[should_panic] // liquid-rust#251
 fn test_round() {
     assert_template_result!("5", r#"{{ input | round }}"#, o!({"input": 4.6}));
     assert_template_result!("4", r#"{{ "4.3" | round }}"#);
@@ -1094,7 +1091,6 @@ fn test_round() {
 }
 
 #[test]
-#[should_panic] // liquid-rust#251
 fn test_ceil() {
     assert_template_result!("5", r#"{{ input | ceil }}"#, o!({"input": 4.6}));
     assert_template_result!("5", r#"{{ "4.3" | ceil }}"#);
@@ -1104,7 +1100,6 @@ fn test_ceil() {
 }
 
 #[test]
-#[should_panic] // liquid-rust#251
 fn test_floor() {
     assert_template_result!("4", r#"{{ input | floor }}"#, o!({"input": 4.6}));
     assert_template_result!("4", r#"{{ "4.3" | floor }}"#);