mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-26 19:56:48 -06:00
Conditional formatting: text rules never match an error value (#1162)
In Excel the "contains", "begins with" and "ends with" rules are SEARCH/LEFT/RIGHT formulas, which fail on an error value, so an error cell is never formatted by them and always matches "does not contain". GridCraft matched on the error's display text instead, so #N/A "contained" a and "began with" #. Skip error values in the three positive rules and match them in notContainsText, with a regression test over =NA(), =1/0 and text cells.
This commit is contained in:
+36
-4
@@ -147,10 +147,18 @@ impl CfCache {
|
||||
CfRule::Expression { formula, style } => {
|
||||
gridcraft_calc::evaluate(wb, sheet, c, &relative(formula, first, c)).to_bool().unwrap_or(false).then_some(style.as_ref())
|
||||
}
|
||||
CfRule::ContainsText { text: t, style } => text.to_lowercase().contains(&t.to_lowercase()).then_some(style.as_ref()),
|
||||
CfRule::NotContainsText { text: t, style } => (!text.to_lowercase().contains(&t.to_lowercase())).then_some(style.as_ref()),
|
||||
CfRule::BeginsWith { text: t, style } => text.to_lowercase().starts_with(&t.to_lowercase()).then_some(style.as_ref()),
|
||||
CfRule::EndsWith { text: t, style } => text.to_lowercase().ends_with(&t.to_lowercase()).then_some(style.as_ref()),
|
||||
// As in Excel, an error value never contains, begins or ends with anything (its rule
|
||||
// formulas SEARCH/LEFT/RIGHT fail on it), so it always "does not contain" (#1162).
|
||||
CfRule::ContainsText { text: t, style } => {
|
||||
(!v.is_error() && text.to_lowercase().contains(&t.to_lowercase())).then_some(style.as_ref())
|
||||
}
|
||||
CfRule::NotContainsText { text: t, style } => {
|
||||
(v.is_error() || !text.to_lowercase().contains(&t.to_lowercase())).then_some(style.as_ref())
|
||||
}
|
||||
CfRule::BeginsWith { text: t, style } => {
|
||||
(!v.is_error() && text.to_lowercase().starts_with(&t.to_lowercase())).then_some(style.as_ref())
|
||||
}
|
||||
CfRule::EndsWith { text: t, style } => (!v.is_error() && text.to_lowercase().ends_with(&t.to_lowercase())).then_some(style.as_ref()),
|
||||
CfRule::Blanks { style } => (v.is_empty() || text.trim().is_empty()).then_some(style.as_ref()),
|
||||
CfRule::NoBlanks { style } => (!v.is_empty() && !text.trim().is_empty()).then_some(style.as_ref()),
|
||||
CfRule::Errors { style } => v.is_error().then_some(style.as_ref()),
|
||||
@@ -410,4 +418,28 @@ mod tests {
|
||||
let mut look = |a: &str| cache.look(&d.wb, 0, CellRef::parse(a).unwrap()).and_then(|l| l.style).is_some();
|
||||
assert_eq!([look("A1"), look("A2")], [true, false]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_rules_skip_error_values() {
|
||||
let mut s = crate::Session::new();
|
||||
s.new_workbook();
|
||||
let values = json!([["=NA()", "=NA()", "=1/0", "=NA()"], ["abc", "#x", "x!", "abc"], ["xyz", "y", "y", "xyz"]]);
|
||||
s.execute("range.setValues", json!({"range": "A1", "values": values})).unwrap();
|
||||
let rule = |range: &str, kind: &str, text: &str| json!({"range": range, "rule": {"type": kind, "text": text, "preset": "lightRedFill"}});
|
||||
s.execute("home.conditionalFormat", rule("A1:A3", "containsText", "a")).unwrap();
|
||||
s.execute("home.conditionalFormat", rule("B1:B3", "beginsWith", "#")).unwrap();
|
||||
s.execute("home.conditionalFormat", rule("C1:C3", "endsWith", "!")).unwrap();
|
||||
s.execute("home.conditionalFormat", rule("D1:D3", "notContainsText", "a")).unwrap();
|
||||
let d = s.doc().unwrap();
|
||||
let mut cache = CfCache::new();
|
||||
let mut look = |a: &str| cache.look(&d.wb, 0, CellRef::parse(a).unwrap()).and_then(|l| l.style).is_some();
|
||||
// Contains "a": abc, never #N/A although its text holds an "a".
|
||||
assert_eq!([look("A1"), look("A2"), look("A3")], [false, true, false]);
|
||||
// Begins with "#": #x, never #N/A.
|
||||
assert_eq!([look("B1"), look("B2"), look("B3")], [false, true, false]);
|
||||
// Ends with "!": x!, never #DIV/0!.
|
||||
assert_eq!([look("C1"), look("C2"), look("C3")], [false, true, false]);
|
||||
// Does not contain "a": #N/A and xyz, not abc.
|
||||
assert_eq!([look("D1"), look("D2"), look("D3")], [true, false, true]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user