Add diffs to EXPECT_EQ.

Previously, the user would have to manually write:
EXPECT_EQ(a, b) << "Want:\n" << b << "\nGot:\n" << a;

The vast majority of the time this got shortened to on of:
// Where does one end and the other begin? Which one is which?
// How do you detect a single-word or single-character diff?
EXPECT_EQ(a, b) << b << "\n" << a;
// It just prints "failure" and nothing else.
EXPECT_EQ(a, b);

Which made it almost impossible to understand error mesasges GN output
for both humans and AI.

This change uses git to pretty-print a diff for test failures (with
color!), falling back to a simple Want:\n...\nGot:\n... format

Change-Id: Icc77e607fcba1bce1e76b60ffb4746a56a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/21960
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/compile_commands_writer_unittest.cc b/src/gn/compile_commands_writer_unittest.cc
index 81ec2e2..f6de442 100644
--- a/src/gn/compile_commands_writer_unittest.cc
+++ b/src/gn/compile_commands_writer_unittest.cc
@@ -712,7 +712,7 @@
       "  }\n"
       "]\n";
 #endif
-  EXPECT_EQ(expected, out) << expected << "\n" << out;
+  EXPECT_EQ(expected, out);
 }
 
 TEST_F(CompileCommandsTest, CollectTargets) {
diff --git a/src/gn/json_project_writer_unittest.cc b/src/gn/json_project_writer_unittest.cc
index 770e7cf..a050b09 100644
--- a/src/gn/json_project_writer_unittest.cc
+++ b/src/gn/json_project_writer_unittest.cc
@@ -274,7 +274,7 @@
    }
 }
 )_";
-  EXPECT_EQ(expected_json, out) << out;
+  EXPECT_EQ(expected_json, out);
 }
 
 TEST_F(JSONWriter, RustTarget) {
@@ -514,7 +514,7 @@
    }
 }
 )_";
-  EXPECT_EQ(expected_json, out) << out;
+  EXPECT_EQ(expected_json, out);
 }
 
 TEST_F(JSONWriter, ForEachWithResponseFile) {
@@ -778,7 +778,7 @@
    }
 }
 )_";
-  EXPECT_EQ(expected_json, out) << out;
+  EXPECT_EQ(expected_json, out);
 }
 
 TEST_F(JSONWriter, FilterTargetsWithDataDeps) {
diff --git a/src/gn/ninja_action_target_writer_unittest.cc b/src/gn/ninja_action_target_writer_unittest.cc
index fa2939e..e855582 100644
--- a/src/gn/ninja_action_target_writer_unittest.cc
+++ b/src/gn/ninja_action_target_writer_unittest.cc
@@ -604,7 +604,7 @@
         "\n"
         "build phony/foo/foo: phony foo.out\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
diff --git a/src/gn/ninja_binary_target_writer_unittest.cc b/src/gn/ninja_binary_target_writer_unittest.cc
index 29dfd33..51b3369 100644
--- a/src/gn/ninja_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_binary_target_writer_unittest.cc
@@ -79,7 +79,7 @@
       "\n"
       "\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaBinaryTargetWriterTest, NoSourcesStaticLib) {
@@ -149,7 +149,7 @@
         "\n"
         "build phony/foo/bar: phony obj/foo/bar.source1.o\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   {
@@ -192,6 +192,6 @@
         "build phony/foo/bar: phony obj/foo/bar.source1.o "
         "obj/foo/bar.source2.o\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
diff --git a/src/gn/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc
index 81fb1ed..8929e06 100644
--- a/src/gn/ninja_c_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -69,7 +69,7 @@
         "build phony/foo/bar: phony obj/foo/bar.input1.o "
         "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // A shared library that depends on the source set.
@@ -106,7 +106,7 @@
         "  output_extension = .so\n"
         "  output_dir =\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // A static library that depends on the source set (should not link it).
@@ -137,7 +137,7 @@
         "  output_extension =\n"
         "  output_dir =\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // Make the static library 'complete', which means it should be linked.
@@ -166,7 +166,7 @@
         "  output_extension =\n"
         "  output_dir =\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -227,7 +227,7 @@
       "  output_extension =\n"
       "  output_dir =\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, CompleteStaticLibrary) {
@@ -277,7 +277,7 @@
         "  output_extension =\n"
         "  output_dir =\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // Make the dependent static library complete.
@@ -309,7 +309,7 @@
         "  output_extension =\n"
         "  output_dir =\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -374,7 +374,7 @@
       "  output_dir = foo\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, NoHardDepsToNoPublicHeaderTarget) {
@@ -560,7 +560,7 @@
       "  output_dir =\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Tests frameworks are applied.
@@ -626,7 +626,7 @@
       "  output_dir =\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, EmptyOutputExtension) {
@@ -678,7 +678,7 @@
       "  output_dir =\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, SourceSetDataDeps) {
@@ -1172,8 +1172,7 @@
         "build withpch/phony/foo/pch_target: "
         "phony withpch/obj/foo/pch_target.input1.o "
         "withpch/obj/foo/pch_target.input2.o\n";
-    EXPECT_EQ(pch_gcc_expected, out.str()) << pch_gcc_expected << "\n"
-                                           << out.str();
+    EXPECT_EQ(pch_gcc_expected, out.str());
   }
 }
 
@@ -1432,7 +1431,7 @@
       "  output_dir =\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Test linking of Rust dependencies into C targets.
@@ -1619,7 +1618,7 @@
       "obj/priv_in_staticlib/libpriv_in_staticlib.rlib\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Test linking of Rust dependencies into C targets. Proc-macro dependencies are
@@ -1786,7 +1785,7 @@
       "obj/pub_in_procmacro_and_rlib/libpub_in_procmacro_and_rlib.rlib\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Test linking of Rust dependencies into C targets.
@@ -1854,7 +1853,7 @@
       "  output_dir =\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, RustDepsOverDynamicLinking) {
@@ -1959,7 +1958,7 @@
       "  rlibs = obj/near/libnear.rlib\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, LinkingWithRustLibraryDepsOnCdylib) {
@@ -2057,7 +2056,7 @@
       "  rlibs = obj/rlib/librlib.rlib\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, LinkingWithRustLibraryDepsOnDylib) {
@@ -2155,7 +2154,7 @@
       "  rlibs = obj/rlib/librlib.rlib\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Verify dependencies of a shared library and a rust library are inherited
@@ -2264,7 +2263,7 @@
       "  rlibs = obj/rlib2/libmyrlib2.rlib\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, ModuleMapInStaticLibrary) {
@@ -2306,7 +2305,7 @@
       "  output_extension =\n"
       "  output_dir =\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, ModuleMapInSourceSet) {
@@ -2345,7 +2344,7 @@
       "\n"
       "build phony/foo/bar: phony obj/foo/bar.bar.o obj/foo/bar.bar.pcm\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Test linking of targets containing Swift modules.
@@ -2388,7 +2387,7 @@
         " obj/foo/file1.o obj/foo/file2.o\n";
 
     const std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // Swift module_dirs correctly set if dependency between Swift modules.
@@ -2426,7 +2425,7 @@
         "|| phony/foo/foo\n";
 
     const std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // Swift module_dirs correctly set if dependency between Swift modules,
@@ -2472,7 +2471,7 @@
         "|| phony/bar/group phony/foo/foo\n";
 
     const std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // C target links with module.
@@ -2508,7 +2507,7 @@
         "  output_dir =\n";
 
     const std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -2614,7 +2613,7 @@
 )";
 
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target target2(&module_settings, Label(SourceDir("//stuff/"), "b",
@@ -2663,7 +2662,7 @@
 )";
 
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target target3(&module_settings, Label(SourceDir("//things/"), "c",
@@ -2707,7 +2706,7 @@
 )";
 
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target depender(&module_settings, Label(SourceDir("//zap/"), "c",
@@ -2755,7 +2754,7 @@
 )";
 
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -2815,7 +2814,7 @@
 #endif
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, Pool) {
@@ -2861,7 +2860,7 @@
       "  output_dir =\n"
       "  pool = foo_pool\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, ToolInputs) {
@@ -2925,7 +2924,7 @@
       "  output_extension =\n"
       "  output_dir =\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, ModuleMapGeneration) {
@@ -2990,8 +2989,7 @@
       "}\n";
 
   std::string modulemap_str = modulemap_out.str();
-  EXPECT_EQ(expected_modulemap, modulemap_str) << expected_modulemap << "\n"
-                                               << modulemap_str;
+  EXPECT_EQ(expected_modulemap, modulemap_str);
 
   const char expected_ninja[] =
       "defines =\n"
@@ -3010,7 +3008,7 @@
       "build phony/foo/bar: phony obj/foo/bar.source1.o\n";
   writer.Run();
   std::string ninja_str = ninja_out.str();
-  EXPECT_EQ(expected_ninja, ninja_str) << expected_ninja << "\n" << ninja_str;
+  EXPECT_EQ(expected_ninja, ninja_str);
 
   // Test generation without explicit public headers (uses sources instead)
   Target target_no_public(
@@ -3042,9 +3040,7 @@
       "}\n";
 
   std::string modulemap_str_no_public = modulemap_out_no_public.str();
-  EXPECT_EQ(expected_modulemap_no_public, modulemap_str_no_public)
-      << expected_modulemap_no_public << "\n"
-      << modulemap_str_no_public;
+  EXPECT_EQ(expected_modulemap_no_public, modulemap_str_no_public);
 
   Target transitive(&module_settings, Label(SourceDir("//foo/"), "transitive",
                                             module_toolchain.label().dir(),
@@ -3119,8 +3115,7 @@
       "  use \"//foo:public_dep\"\n"
       "  export *\n"
       "}\n";
-  EXPECT_EQ(expected_public, public_modulemap.str()) << expected_public << "\n"
-                                                     << public_modulemap.str();
+  EXPECT_EQ(expected_public, public_modulemap.str());
 
   std::ostringstream private_modulemap;
   NinjaCBinaryTargetWriter(&root, ninja_out)
@@ -3138,9 +3133,7 @@
       "  use \"//private:private_dep\"\n"
       "}\n";
 
-  EXPECT_EQ(expected_private, private_modulemap.str())
-      << expected_private << "\n"
-      << private_modulemap.str();
+  EXPECT_EQ(expected_private, private_modulemap.str());
 
   std::ostringstream root_ninja_out;
   NinjaCBinaryTargetWriter(&root, root_ninja_out).Run();
@@ -3160,6 +3153,5 @@
       "\n"
       "build phony/foo/root: phony obj/foo/root.root.o\n";
 
-  EXPECT_EQ(expected_root_ninja, root_ninja_str) << expected_root_ninja << "\n"
-                                                 << root_ninja_str;
+  EXPECT_EQ(expected_root_ninja, root_ninja_str);
 }
diff --git a/src/gn/ninja_create_bundle_target_writer_unittest.cc b/src/gn/ninja_create_bundle_target_writer_unittest.cc
index d79b719..3dfd6a3 100644
--- a/src/gn/ninja_create_bundle_target_writer_unittest.cc
+++ b/src/gn/ninja_create_bundle_target_writer_unittest.cc
@@ -170,7 +170,7 @@
       "baz/bar/bar_partial_info.plist || phony/foo/bar\n"
       "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Tests multiple files from asset catalog.
@@ -276,7 +276,7 @@
       "build phony/baz/bar: phony || phony/foo/action\n"
       "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Tests complex target with multiple bundle_data sources, including
@@ -420,7 +420,7 @@
       "baz/bar/bar_partial_info.plist || phony/baz/bar.inputdeps\n"
       "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Tests post-processing step.
@@ -500,7 +500,7 @@
       "bar.bundle/_CodeSignature/CodeResources || phony/baz/bar.inputdeps\n"
       "build bar.bundle: phony phony/baz/bar\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << out_str << "\n" << expected;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST(NinjaCreateBundleTargetWriter, PostProcessingNoStampFilesCustomToolchain) {
@@ -587,5 +587,5 @@
       "toolchain/phony/baz/bar.inputdeps\n"
       "build bar.bundle: phony toolchain/phony/baz/bar\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
diff --git a/src/gn/ninja_outputs_writer_unittest.cc b/src/gn/ninja_outputs_writer_unittest.cc
index a5f8a67..154d84b 100644
--- a/src/gn/ninja_outputs_writer_unittest.cc
+++ b/src/gn/ninja_outputs_writer_unittest.cc
@@ -151,5 +151,5 @@
   ]
 })##";
 
-  EXPECT_EQ(generated, expected) << generated << "\n" << expected;
+  EXPECT_EQ(generated, expected);
 }
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index 11b8071..680652c 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -74,7 +74,7 @@
         "  ldflags = -fsanitize=address\n"
         "  sources = ../../foo/input3.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -129,7 +129,7 @@
         "  ldflags =\n"
         "  sources = ../../baz/privatelib.rs ../../baz/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target far_public_rlib(setup.settings(),
@@ -171,7 +171,7 @@
         "  ldflags =\n"
         "  sources = ../../far/farlib.rs ../../far/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target public_rlib(setup.settings(), Label(SourceDir("//bar/"), "publiclib"));
@@ -213,7 +213,7 @@
         "  ldflags =\n"
         "  sources = ../../bar/publiclib.rs ../../bar/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target rlib(setup.settings(), Label(SourceDir("//foo/"), "direct"));
@@ -274,7 +274,7 @@
         "  ldflags =\n"
         "  sources = ../../main/source.rs ../../main/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -322,7 +322,7 @@
         "  ldflags =\n"
         "  sources = ../../faz/private_inside.rs ../../faz/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target inside_dylib(setup.settings(), Label(SourceDir("//baz/"), "inside"));
@@ -363,7 +363,7 @@
         "  ldflags =\n"
         "  sources = ../../baz/inside.rs ../../baz/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target dylib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
@@ -409,7 +409,7 @@
         "  ldflags =\n"
         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target private_dylib(setup.settings(),
@@ -485,7 +485,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -532,7 +532,7 @@
         "  ldflags =\n"
         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   // A group produces an order-only dependency in ninja:
@@ -593,7 +593,7 @@
         "  ldflags =\n"
         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
@@ -637,7 +637,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -731,7 +731,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -836,7 +836,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target nonrust_only(setup.settings(), Label(SourceDir("//foo/"), "bar"));
@@ -877,7 +877,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target rstaticlib(setup.settings(), Label(SourceDir("//baz/"), "baz"));
@@ -920,7 +920,7 @@
         "  ldflags =\n"
         "  sources = ../../baz/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1109,7 +1109,7 @@
       "  sources = ../../exe/main.rs\n";
 
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 TEST_F(NinjaRustBinaryTargetWriterTest, RustOutputExtensionAndDir) {
@@ -1156,7 +1156,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/input3.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1226,7 +1226,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/input.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1326,7 +1326,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/input.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1412,7 +1412,7 @@
         "  ldflags =\n"
         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
@@ -1454,7 +1454,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1500,7 +1500,7 @@
         "  ldflags =\n"
         "  sources = ../../bar/mylib.rs ../../bar/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target group(setup.settings(), Label(SourceDir("//baz/"), "group"));
@@ -1550,7 +1550,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1605,7 +1605,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1657,7 +1657,7 @@
         "  sources = ../../foo/source.rs ../../foo/main.rs "
         "../../foo/config.json ../../foo/template.h\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1700,7 +1700,7 @@
         "  ldflags =\n"
         "  sources = ../../bar/lib.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 
   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
@@ -1741,7 +1741,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1819,7 +1819,7 @@
         "  ldflags =\n"
         "  sources = ../../foo/main.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1917,7 +1917,7 @@
         "  ldflags =\n"
         "  sources = ../../linked/exe.rs\n";
     std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+    EXPECT_EQ(expected, out_str);
   }
 }
 
@@ -1967,7 +1967,7 @@
       "  sources = ../../foo/source.rs\n"
       "  pool = foo_pool\n";
   std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Tests frameworks are applied.
@@ -2041,7 +2041,7 @@
       "  ldflags =\n"
       "  sources = ../../linked/exe.rs\n";
   const std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
 
 // Test linking of targets containing Swift modules.
@@ -2102,5 +2102,5 @@
       "  sources = ../../linked/exe.rs\n";
 
   const std::string out_str = out.str();
-  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  EXPECT_EQ(expected, out_str);
 }
diff --git a/src/gn/output_conversion_unittest.cc b/src/gn/output_conversion_unittest.cc
index 1eaf2ab..3e1b957 100644
--- a/src/gn/output_conversion_unittest.cc
+++ b/src/gn/output_conversion_unittest.cc
@@ -263,8 +263,7 @@
   ConvertValueToOutput(settings(), result, Value(nullptr, "string"), reverse,
                        &err);
   EXPECT_FALSE(err.has_error());
-  EXPECT_EQ(reverse.str(), input)
-      << "actual: " << reverse.str() << "expected:" << input;
+  EXPECT_EQ(reverse.str(), input);
 }
 
 TEST_F(OutputConversionTest, ReverseListLines) {
@@ -278,8 +277,7 @@
   ConvertValueToOutput(settings(), result, Value(nullptr, "list lines"),
                        reverse, &err);
   EXPECT_FALSE(err.has_error());
-  EXPECT_EQ(reverse.str(), input)
-      << "actual: " << reverse.str() << "expected:" << input;
+  EXPECT_EQ(reverse.str(), input);
 }
 
 TEST_F(OutputConversionTest, ReverseValueString) {
@@ -293,8 +291,7 @@
   ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse,
                        &err);
   EXPECT_FALSE(err.has_error());
-  EXPECT_EQ(reverse.str(), input)
-      << "actual: " << reverse.str() << "expected:" << input;
+  EXPECT_EQ(reverse.str(), input);
 }
 
 TEST_F(OutputConversionTest, ReverseValueInt) {
@@ -308,8 +305,7 @@
   ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse,
                        &err);
   EXPECT_FALSE(err.has_error());
-  EXPECT_EQ(reverse.str(), input)
-      << "actual: " << reverse.str() << "expected:" << input;
+  EXPECT_EQ(reverse.str(), input);
 }
 
 TEST_F(OutputConversionTest, ReverseValueList) {
@@ -323,8 +319,7 @@
   ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse,
                        &err);
   EXPECT_FALSE(err.has_error());
-  EXPECT_EQ(reverse.str(), input)
-      << "actual: " << reverse.str() << "expected:" << input;
+  EXPECT_EQ(reverse.str(), input);
 }
 
 TEST_F(OutputConversionTest, ReverseValueDict) {
@@ -338,8 +333,7 @@
   ConvertValueToOutput(settings(), result, Value(nullptr, "scope"), reverse,
                        &err);
   EXPECT_FALSE(err.has_error());
-  EXPECT_EQ(reverse.str(), input)
-      << "actual: " << reverse.str() << "expected:" << input;
+  EXPECT_EQ(reverse.str(), input);
 }
 
 TEST_F(OutputConversionTest, ReverseValueEmpty) {
diff --git a/src/gn/standard_out.cc b/src/gn/standard_out.cc
index 85cd665..ec8efde 100644
--- a/src/gn/standard_out.cc
+++ b/src/gn/standard_out.cc
@@ -97,6 +97,11 @@
 
 }  // namespace
 
+bool IsColorEnabled() {
+  EnsureInitialized();
+  return is_console;
+}
+
 #if defined(OS_WIN)
 
 void OutputString(const std::string& output,
diff --git a/src/gn/standard_out.h b/src/gn/standard_out.h
index 9850c0e..b737fa1 100644
--- a/src/gn/standard_out.h
+++ b/src/gn/standard_out.h
@@ -59,4 +59,6 @@
 // be emitted. Used only in markdown mode.
 void PrintLongHelp(const std::string& text, const std::string& tag = "");
 
+bool IsColorEnabled();
+
 #endif  // TOOLS_GN_STANDARD_OUT_H_
diff --git a/src/util/test/gn_test.cc b/src/util/test/gn_test.cc
index 6e9b964..069fad2 100644
--- a/src/util/test/gn_test.cc
+++ b/src/util/test/gn_test.cc
@@ -18,7 +18,11 @@
 #include <string.h>
 
 #include "base/command_line.h"
-#include "util/build_config.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/stringprintf.h"
+#include "gn/exec_process.h"
+#include "gn/standard_out.h"
 #include "util/test/test.h"
 
 #if defined(OS_WIN)
@@ -29,6 +33,52 @@
 
 namespace testing {
 Test* g_current_test;
+
+std::string DiffStrings(std::string_view expected, std::string_view actual) {
+  base::ScopedTempDir temp_dir;
+  auto fallback = [&]() {
+    return base::StringPrintf(
+        "Expected:\n%.*s\n\nActual:\n%.*s", static_cast<int>(expected.size()),
+        expected.data(), static_cast<int>(actual.size()), actual.data());
+  };
+  if (!temp_dir.CreateUniqueTempDir()) {
+    return fallback();
+  }
+
+  base::FilePath expected_path = temp_dir.GetPath().AppendASCII("expected.txt");
+  base::FilePath actual_path = temp_dir.GetPath().AppendASCII("actual.txt");
+
+  if (base::WriteFile(expected_path, expected.data(), expected.size()) !=
+      static_cast<int>(expected.size())) {
+    return fallback();
+  }
+  if (base::WriteFile(actual_path, actual.data(), actual.size()) !=
+      static_cast<int>(actual.size())) {
+    return fallback();
+  }
+
+  base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
+  cmdline.SetParseSwitches(false);
+  cmdline.SetProgram(base::FilePath(FILE_PATH_LITERAL("git")));
+  cmdline.AppendArg("diff");
+  cmdline.AppendArg("--no-index");
+  if (::IsColorEnabled()) {
+    cmdline.AppendArg("--color");
+  }
+  cmdline.AppendArgPath(expected_path);
+  cmdline.AppendArgPath(actual_path);
+
+  std::string output;
+  std::string stderr_output;
+  int exit_code = 0;
+  ::internal::ExecProcess(cmdline, base::FilePath(FILE_PATH_LITERAL(".")),
+                          &output, &stderr_output, &exit_code);
+  if (output.empty()) {
+    return fallback();
+  }
+  return output;
+}
+
 }  // namespace testing
 
 struct RegisteredTest {
diff --git a/src/util/test/test.h b/src/util/test/test.h
index d3fc056..2419963 100644
--- a/src/util/test/test.h
+++ b/src/util/test/test.h
@@ -9,6 +9,8 @@
 
 #include <sstream>
 #include <string>
+#include <string_view>
+#include <type_traits>
 
 // This is a minimal googletest-like testing framework. It's originally derived
 // from Ninja's src/test.h. You might prefer that one if you have different
@@ -80,6 +82,19 @@
   const char* error_;
 };
 
+std::string DiffStrings(std::string_view expected, std::string_view actual);
+
+template <typename T, typename U>
+std::string TryDiffStrings(const T& expected, const U& actual) {
+  // Try to diff if they are strings
+  if constexpr (std::is_convertible_v<T, std::string_view> &&
+                std::is_convertible_v<U, std::string_view>) {
+    return DiffStrings(expected, actual);
+  } else {
+    return "";
+  }
+}
+
 }  // namespace testing
 
 void RegisterTest(testing::Test* (*)(), const char*);
@@ -125,9 +140,14 @@
   return ::testing::AssertHelper(__FILE__, __LINE__, message) = \
              ::testing::Message()
 
-#define EXPECT_EQ(a, b)                                     \
-  TEST_ASSERT_(::testing::TestResult(a == b, #a " == " #b), \
-               TEST_NONFATAL_FAILURE_)
+#define EXPECT_EQ(a, b)                                        \
+  TEST_AMBIGUOUS_ELSE_BLOCKER_                                 \
+  if (const ::testing::TestResult test_result =                \
+          ::testing::TestResult(a == b, #a " == " #b))         \
+    ;                                                          \
+  else                                                         \
+    ::testing::AssertHelper(__FILE__, __LINE__, test_result) = \
+        ::testing::Message() << ::testing::TryDiffStrings(a, b)
 
 #define EXPECT_NE(a, b)                                     \
   TEST_ASSERT_(::testing::TestResult(a != b, #a " != " #b), \
@@ -161,8 +181,14 @@
   TEST_ASSERT_(::testing::TestResult(strcmp(a, b) == 0, #a " str== " #b), \
                TEST_NONFATAL_FAILURE_)
 
-#define ASSERT_EQ(a, b) \
-  TEST_ASSERT_(::testing::TestResult(a == b, #a " == " #b), TEST_FATAL_FAILURE_)
+#define ASSERT_EQ(a, b)                                               \
+  TEST_AMBIGUOUS_ELSE_BLOCKER_                                        \
+  if (const ::testing::TestResult test_result =                       \
+          ::testing::TestResult(a == b, #a " == " #b))                \
+    ;                                                                 \
+  else                                                                \
+    return ::testing::AssertHelper(__FILE__, __LINE__, test_result) = \
+               ::testing::Message() << ::testing::TryDiffStrings(a, b)
 
 #define ASSERT_NE(a, b) \
   TEST_ASSERT_(::testing::TestResult(a != b, #a " != " #b), TEST_FATAL_FAILURE_)