diff --git a/README.md b/README.md index 67afb619..c51423ec 100644 --- a/README.md +++ b/README.md @@ -297,9 +297,10 @@ displayed, we recommend setting those variables in the personal ### Configuration variable list -| Variable name | Description | -| ------------------- | -------------------------------------------------- | -| GTEST_RUST_NO_COLOR | If set to any value, disables ANSI output from the failure message. This is useful when the failure description is piped to a file or another process. | +| Variable name | Description | +| ------------- | ------------------------------------------------------- | +| NO_COLOR | Disables coloured output. See . | +| FORCE_COLOR | Forces colours even when the output is piped to a file. | ## Contributing Changes diff --git a/googletest/Cargo.toml b/googletest/Cargo.toml index 62778dcb..601c3ceb 100644 --- a/googletest/Cargo.toml +++ b/googletest/Cargo.toml @@ -34,8 +34,9 @@ authors = [ googletest_macro = { path = "../googletest_macro", version = "0.9.0" } anyhow = { version = "1", optional = true } num-traits = "0.2.15" -regex = "1.6.0" proptest = { version = "1.2.0", optional = true } +regex = "1.6.0" +rustversion = "1.0.14" [dev-dependencies] indoc = "2" diff --git a/googletest/config.toml b/googletest/config.toml new file mode 100644 index 00000000..7bc2412e --- /dev/null +++ b/googletest/config.toml @@ -0,0 +1,2 @@ +[env] +NO_COLOR = "1" diff --git a/googletest/src/matcher_support/summarize_diff.rs b/googletest/src/matcher_support/summarize_diff.rs index 6981496f..53f43807 100644 --- a/googletest/src/matcher_support/summarize_diff.rs +++ b/googletest/src/matcher_support/summarize_diff.rs @@ -14,14 +14,13 @@ #![doc(hidden)] -use std::borrow::Cow; -use std::fmt::{Display, Write}; - use crate::matcher_support::edit_distance; - -/// Environment variable controlling the usage of ansi color in difference -/// summary. -const NO_COLOR_VAR: &str = "GTEST_RUST_NO_COLOR"; +#[rustversion::since(1.70)] +use std::io::IsTerminal; +use std::{ + borrow::Cow, + fmt::{Display, Write}, +}; /// Returns a string describing how the expected and actual lines differ. /// @@ -195,7 +194,7 @@ struct StyledLine<'a> { impl<'a> Display for StyledLine<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if std::env::var(NO_COLOR_VAR).is_err() { + if stdout_supports_colour() { write!( f, "{}{}{}{}", @@ -207,36 +206,29 @@ impl<'a> Display for StyledLine<'a> { } } +#[rustversion::since(1.70)] +fn stdout_supports_colour() -> bool { + match (is_env_var_set("NO_COLOR"), is_env_var_set("FORCE_COLOR")) { + (true, _) => false, + (false, true) => true, + (false, false) => std::io::stdout().is_terminal(), + } +} + +#[rustversion::not(since(1.70))] +fn stdout_supports_colour() -> bool { + is_env_var_set("FORCE_COLOR") +} + +fn is_env_var_set(var: &'static str) -> bool { + std::env::var(var).map(|s| !s.is_empty()).unwrap_or(false) +} + #[cfg(test)] mod tests { use super::*; use crate::{matcher_support::edit_distance::Mode, prelude::*}; use indoc::indoc; - use serial_test::serial; - - #[must_use] - fn remove_var() -> TempVar { - let old_value = std::env::var(NO_COLOR_VAR); - std::env::remove_var(NO_COLOR_VAR); - TempVar(old_value.ok()) - } - - #[must_use] - fn set_var(var: &str) -> TempVar { - let old_value = std::env::var(NO_COLOR_VAR); - std::env::set_var(NO_COLOR_VAR, var); - TempVar(old_value.ok()) - } - struct TempVar(Option); - - impl Drop for TempVar { - fn drop(&mut self) { - match &self.0 { - Some(old_var) => std::env::set_var(NO_COLOR_VAR, old_var), - None => std::env::remove_var(NO_COLOR_VAR), - } - } - } // Make a long text with each element of the iterator on one line. // `collection` must contains at least one element. @@ -277,30 +269,8 @@ mod tests { } #[test] - #[serial] - fn create_diff_exact_small_difference() -> Result<()> { - let _cleanup = remove_var(); - - verify_that!( - create_diff(&build_text(1..50), &build_text(1..51), Mode::Exact), - eq(indoc! { - " - - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): - 1 - 2 - \x1B[3m<---- 45 common lines omitted ---->\x1B[0m - 48 - 49 - +\x1B[1;32m50\x1B[0m" - }) - ) - } - - #[test] - #[serial] fn create_diff_exact_small_difference_no_color() -> Result<()> { - let _cleanup = set_var("NO_COLOR"); + std::env::set_var("NO_COLOR", "1"); verify_that!( create_diff(&build_text(1..50), &build_text(1..51), Mode::Exact), diff --git a/googletest/src/matchers/display_matcher.rs b/googletest/src/matchers/display_matcher.rs index 3c110acb..628769be 100644 --- a/googletest/src/matchers/display_matcher.rs +++ b/googletest/src/matchers/display_matcher.rs @@ -108,10 +108,10 @@ mod tests { err(displays_as(contains_substring(indoc!( " which displays as a string which isn't equal to \"123\\n345\" - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): 123 - -\x1B[1;31m234\x1B[0m - +\x1B[1;32m345\x1B[0m + -234 + +345 " )))) ) diff --git a/googletest/src/matchers/eq_deref_of_matcher.rs b/googletest/src/matchers/eq_deref_of_matcher.rs index cb810ead..15409058 100644 --- a/googletest/src/matchers/eq_deref_of_matcher.rs +++ b/googletest/src/matchers/eq_deref_of_matcher.rs @@ -138,12 +138,12 @@ mod tests { " Actual: Strukt { int: 123, string: \"something\" }, which isn't equal to Strukt { int: 321, string: \"someone\" } - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): Strukt { - -\x1B[1;31m int: 123,\x1B[0m - +\x1B[1;32m int: 321,\x1B[0m - -\x1B[1;31m string: \"something\",\x1B[0m - +\x1B[1;32m string: \"someone\",\x1B[0m + - int: 123, + + int: 321, + - string: \"something\", + + string: \"someone\", } "}))) ) diff --git a/googletest/src/matchers/eq_matcher.rs b/googletest/src/matchers/eq_matcher.rs index fc52ecb2..42684c97 100644 --- a/googletest/src/matchers/eq_matcher.rs +++ b/googletest/src/matchers/eq_matcher.rs @@ -178,12 +178,12 @@ mod tests { " Actual: Strukt { int: 123, string: \"something\" }, which isn't equal to Strukt { int: 321, string: \"someone\" } - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): Strukt { - -\x1B[1;31m int: 123,\x1B[0m - +\x1B[1;32m int: 321,\x1B[0m - -\x1B[1;31m string: \"something\",\x1B[0m - +\x1B[1;32m string: \"someone\",\x1B[0m + - int: 123, + + int: 321, + - string: \"something\", + + string: \"someone\", } "}))) ) @@ -200,12 +200,12 @@ mod tests { Expected: is equal to [1, 3, 4] Actual: [1, 2, 3], which isn't equal to [1, 3, 4] - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): [ 1, - -\x1B[1;31m 2,\x1B[0m + - 2, 3, - +\x1B[1;32m 4,\x1B[0m + + 4, ] "}))) ) @@ -222,12 +222,12 @@ mod tests { Expected: is equal to [1, 3, 5] Actual: [1, 2, 3, 4, 5], which isn't equal to [1, 3, 5] - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): [ 1, - -\x1B[1;31m 2,\x1B[0m + - 2, 3, - -\x1B[1;31m 4,\x1B[0m + - 4, 5, ] "}))) @@ -241,17 +241,17 @@ mod tests { result, err(displays_as(contains_substring(indoc! { " - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): [ - -\x1B[1;31m 1,\x1B[0m - -\x1B[1;31m 2,\x1B[0m + - 1, + - 2, 3, 4, - \x1B[3m<---- 43 common lines omitted ---->\x1B[0m + <---- 43 common lines omitted ----> 48, 49, - +\x1B[1;32m 50,\x1B[0m - +\x1B[1;32m 51,\x1B[0m + + 50, + + 51, ]"}))) ) } @@ -263,17 +263,17 @@ mod tests { result, err(displays_as(contains_substring(indoc! { " - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): [ - -\x1B[1;31m 1,\x1B[0m - -\x1B[1;31m 2,\x1B[0m + - 1, + - 2, 3, 4, 5, 6, 7, - +\x1B[1;32m 8,\x1B[0m - +\x1B[1;32m 9,\x1B[0m + + 8, + + 9, ]"}))) ) } @@ -285,14 +285,14 @@ mod tests { result, err(displays_as(contains_substring(indoc! { " - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): [ 1, - \x1B[3m<---- 46 common lines omitted ---->\x1B[0m + <---- 46 common lines omitted ----> 48, 49, - +\x1B[1;32m 50,\x1B[0m - +\x1B[1;32m 51,\x1B[0m + + 50, + + 51, ]"}))) ) } @@ -304,13 +304,13 @@ mod tests { result, err(displays_as(contains_substring(indoc! { " - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + Difference(-actual / +expected): [ - -\x1B[1;31m 1,\x1B[0m - -\x1B[1;31m 2,\x1B[0m + - 1, + - 2, 3, 4, - \x1B[3m<---- 46 common lines omitted ---->\x1B[0m + <---- 46 common lines omitted ----> 51, ]"}))) ) @@ -357,8 +357,8 @@ mod tests { err(displays_as(contains_substring(indoc!( " First line - -\x1B[1;31mSecond line\x1B[0m - +\x1B[1;32mSecond lines\x1B[0m + -Second line + +Second lines Third line " )))) @@ -380,9 +380,7 @@ mod tests { verify_that!( result, - err(displays_as(not(contains_substring( - "Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m):" - )))) + err(displays_as(not(contains_substring("Difference(-actual / +expected):")))) ) } @@ -401,9 +399,7 @@ mod tests { verify_that!( result, - err(displays_as(not(contains_substring( - "Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m):" - )))) + err(displays_as(not(contains_substring("Difference(-actual / +expected):")))) ) } } diff --git a/googletest/src/matchers/str_matcher.rs b/googletest/src/matchers/str_matcher.rs index c8a510e3..3a4e2e99 100644 --- a/googletest/src/matchers/str_matcher.rs +++ b/googletest/src/matchers/str_matcher.rs @@ -974,8 +974,8 @@ mod tests { err(displays_as(contains_substring(indoc!( " First line - -\x1B[1;31mSecond line\x1B[0m - +\x1B[1;32mSecond lines\x1B[0m + -Second line + +Second lines Third line " )))) @@ -1007,10 +1007,10 @@ mod tests { err(displays_as(contains_substring(indoc!( " First line - -\x1B[1;31mSecond line\x1B[0m - +\x1B[1;32mSecond lines\x1B[0m + -Second line + +Second lines Third line - \x1B[3m<---- remaining lines omitted ---->\x1B[0m + <---- remaining lines omitted ----> " )))) ) @@ -1040,9 +1040,9 @@ mod tests { err(displays_as(contains_substring(indoc!( " First line - -\x1B[1;31mSecond line\x1B[0m - +\x1B[1;32mSecond lines\x1B[0m - \x1B[3m<---- remaining lines omitted ---->\x1B[0m + -Second line + +Second lines + <---- remaining lines omitted ----> " )))) ) @@ -1072,11 +1072,11 @@ mod tests { result, err(displays_as(contains_substring(indoc!( " - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): - \x1B[3m<---- remaining lines omitted ---->\x1B[0m + Difference(-actual / +expected): + <---- remaining lines omitted ----> Second line - +\x1B[1;32mThird lines\x1B[0m - -\x1B[1;31mThird line\x1B[0m + +Third lines + -Third line Fourth line " )))) @@ -1109,13 +1109,13 @@ mod tests { result, err(displays_as(contains_substring(indoc!( " - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): - \x1B[3m<---- remaining lines omitted ---->\x1B[0m + Difference(-actual / +expected): + <---- remaining lines omitted ----> Second line - +\x1B[1;32mThird lines\x1B[0m - -\x1B[1;31mThird line\x1B[0m + +Third lines + -Third line Fourth line - \x1B[3m<---- remaining lines omitted ---->\x1B[0m" + <---- remaining lines omitted ---->" )))) ) } @@ -1146,16 +1146,16 @@ mod tests { result, err(displays_as(contains_substring(indoc!( " - Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): - \x1B[3m<---- remaining lines omitted ---->\x1B[0m - +\x1B[1;32mline\x1B[0m - -\x1B[1;31mSecond line\x1B[0m + Difference(-actual / +expected): + <---- remaining lines omitted ----> + +line + -Second line Third line - +\x1B[1;32mFoorth line\x1B[0m - -\x1B[1;31mFourth line\x1B[0m - +\x1B[1;32mFifth\x1B[0m - -\x1B[1;31mFifth line\x1B[0m - \x1B[3m<---- remaining lines omitted ---->\x1B[0m + +Foorth line + -Fourth line + +Fifth + -Fifth line + <---- remaining lines omitted ----> " )))) ) @@ -1186,10 +1186,10 @@ mod tests { err(displays_as(contains_substring(indoc!( " First line - -\x1B[1;31mSecond line\x1B[0m - +\x1B[1;32mSecond lines\x1B[0m + -Second line + +Second lines Third line - -\x1B[1;31mFourth line\x1B[0m + -Fourth line " )))) ) @@ -1209,9 +1209,7 @@ mod tests { verify_that!( result, - err(displays_as(not(contains_substring( - "Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m):" - )))) + err(displays_as(not(contains_substring("Difference(-actual / +expected):")))) ) } @@ -1230,9 +1228,7 @@ mod tests { verify_that!( result, - err(displays_as(not(contains_substring( - "Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m):" - )))) + err(displays_as(not(contains_substring("Difference(-actual / +expected):")))) ) } } diff --git a/googletest/tests/colourised_diff_test.rs b/googletest/tests/colourised_diff_test.rs new file mode 100644 index 00000000..d1b4ecbd --- /dev/null +++ b/googletest/tests/colourised_diff_test.rs @@ -0,0 +1,52 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use googletest::prelude::*; +use indoc::indoc; +use std::fmt::{Display, Write}; + +// Make a long text with each element of the iterator on one line. +// `collection` must contains at least one element. +fn build_text(mut collection: impl Iterator) -> String { + let mut text = String::new(); + write!(&mut text, "{}", collection.next().expect("Provided collection without elements")) + .unwrap(); + for item in collection { + write!(&mut text, "\n{}", item).unwrap(); + } + text +} + +#[test] +fn colors_appear_when_no_color_is_no_set_and_force_color_is_set() -> Result<()> { + std::env::remove_var("NO_COLOR"); + std::env::set_var("FORCE_COLOR", "1"); + + let result = verify_that!(build_text(1..50), eq(build_text(1..51))); + + verify_that!( + result, + err(displays_as(contains_substring(indoc! { + " + + Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m): + 1 + 2 + \x1B[3m<---- 45 common lines omitted ---->\x1B[0m + 48 + 49 + +\x1B[1;32m50\x1B[0m" + }))) + ) +} diff --git a/googletest/tests/lib.rs b/googletest/tests/lib.rs index f6b3ec10..6cb158e5 100644 --- a/googletest/tests/lib.rs +++ b/googletest/tests/lib.rs @@ -14,6 +14,7 @@ mod all_matcher_test; mod any_matcher_test; +mod colourised_diff_test; mod composition_test; mod elements_are_matcher_test; mod field_matcher_test; diff --git a/googletest/tests/no_color_test.rs b/googletest/tests/no_color_test.rs new file mode 100644 index 00000000..86c40f47 --- /dev/null +++ b/googletest/tests/no_color_test.rs @@ -0,0 +1,54 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(feature = "supports-color")] + +use googletest::prelude::*; +use indoc::indoc; +use std::fmt::{Display, Write}; + +// Make a long text with each element of the iterator on one line. +// `collection` must contains at least one element. +fn build_text(mut collection: impl Iterator) -> String { + let mut text = String::new(); + write!(&mut text, "{}", collection.next().expect("Provided collection without elements")) + .unwrap(); + for item in collection { + write!(&mut text, "\n{}", item).unwrap(); + } + text +} + +#[test] +fn colours_suppressed_when_both_no_color_and_force_color_are_set() -> Result<()> { + std::env::set_var("NO_COLOR", "1"); + std::env::set_var("FORCE_COLOR", "1"); + + let result = verify_that!(build_text(1..50), eq(build_text(1..51))); + + verify_that!( + result, + err(displays_as(contains_substring(indoc! { + " + + Difference(-actual / +expected): + 1 + 2 + <---- 45 common lines omitted ----> + 48 + 49 + +50" + }))) + ) +}