Simplify success expectations in GN.

It is extremely common to do `EXPECT_FALSE(err.has_error())` to check
for success, but users rarely log the error that actually occurred.

This introduces EXPECT_SUCCESS|ASSERT_SUCCESS(err), which automatically
logs the error message if an error occurred.

Change-Id: Id987943fc10274f537d90a1314a97f6c6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/22040
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
diff --git a/src/gn/action_target_generator_unittest.cc b/src/gn/action_target_generator_unittest.cc
index 08ff8af..dd91fe5 100644
--- a/src/gn/action_target_generator_unittest.cc
+++ b/src/gn/action_target_generator_unittest.cc
@@ -27,7 +27,7 @@
   // This should run fine.
   Err err;
   input_good.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   // Same thing with a pattern in the output should fail.
   TestParseInput input_bad(
@@ -76,7 +76,7 @@
          })");
   ASSERT_FALSE(input_resp_file.has_error());
   input_resp_file.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   // Defining a response file but not referencing it should fail.
   err = Err();
diff --git a/src/gn/binary_target_generator_unittest.cc b/src/gn/binary_target_generator_unittest.cc
index ba1ae5a..66add7a 100644
--- a/src/gn/binary_target_generator_unittest.cc
+++ b/src/gn/binary_target_generator_unittest.cc
@@ -23,11 +23,11 @@
            generate_modulemap = "textual"
            sources = [ "//foo.c" ]
          })");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   ASSERT_EQ(1u, items_.size());
   Target* target = items_[0]->AsTarget();
@@ -47,11 +47,11 @@
            generate_modulemap = "textual"
            sources = [ "//foo.cc", "//foo.h" ]
          })");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   ASSERT_EQ(1u, items_.size());
   Target* target = items_[0]->AsTarget();
@@ -74,11 +74,11 @@
            sources = [ "//foo.cc" ]
            public = ["//foo.h"]
          })");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   ASSERT_EQ(1u, items_.size());
   Target* target = items_[0]->AsTarget();
diff --git a/src/gn/builder_unittest.cc b/src/gn/builder_unittest.cc
index 990cb35..8e08fab 100644
--- a/src/gn/builder_unittest.cc
+++ b/src/gn/builder_unittest.cc
@@ -520,7 +520,7 @@
   // There should be no errors (cycle detection passed).
   Err err;
   EXPECT_TRUE(builder_.CheckForBadItems(&err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 }
 
 // Tests that if a validation resolves, the target does NOT write if it
diff --git a/src/gn/commands_unittest.cc b/src/gn/commands_unittest.cc
index 6d861cd..44c91b7 100644
--- a/src/gn/commands_unittest.cc
+++ b/src/gn/commands_unittest.cc
@@ -21,10 +21,10 @@
   Err err;
   LabelPattern pattern_a = LabelPattern::GetPattern(
       current_dir, std::string_view(), Value(nullptr, "//a:*"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   LabelPattern pattern_ef = LabelPattern::GetPattern(
       current_dir, std::string_view(), Value(nullptr, "//e:f"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   std::vector<LabelPattern> label_patterns{pattern_a, pattern_ef};
 
   std::vector<const Target*> output;
diff --git a/src/gn/compile_commands_writer_unittest.cc b/src/gn/compile_commands_writer_unittest.cc
index f6de442..b4aa2b5 100644
--- a/src/gn/compile_commands_writer_unittest.cc
+++ b/src/gn/compile_commands_writer_unittest.cc
@@ -776,7 +776,7 @@
   const std::string source_root("/home/me/build/");
   LabelPattern wildcard_pattern = LabelPattern::GetPattern(
       SourceDir(), source_root, Value(nullptr, "//*"), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   std::vector<const Target*> output = CompileCommandsWriter::CollectTargets(
       build_settings(), targets, std::vector<LabelPattern>{wildcard_pattern},
       std::nullopt, &err);
@@ -791,7 +791,7 @@
   // Collect all deps of "//foo/*".
   LabelPattern foo_wildcard = LabelPattern::GetPattern(
       SourceDir(), source_root, Value(nullptr, "//foo/*"), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   output = CompileCommandsWriter::CollectTargets(
       build_settings(), targets, std::vector<LabelPattern>{foo_wildcard},
       std::nullopt, &err);
@@ -838,7 +838,7 @@
   // union.
   LabelPattern foo_bar2 = LabelPattern::GetPattern(
       SourceDir(), source_root, Value(nullptr, "//foo:bar2"), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   output = CompileCommandsWriter::CollectTargets(
       build_settings(), targets, std::vector<LabelPattern>{foo_bar2},
       std::string("bar1"), &err);
diff --git a/src/gn/config_values_extractors_unittest.cc b/src/gn/config_values_extractors_unittest.cc
index 24efa4c..3b09076 100644
--- a/src/gn/config_values_extractors_unittest.cc
+++ b/src/gn/config_values_extractors_unittest.cc
@@ -197,7 +197,7 @@
   ConfigValuesGenerator gen(&config_values, setup.scope(), SourceDir("//foo/"),
                             &err);
   gen.Run();
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(config_values.c_additional_outputs().size(), 1u);
   EXPECT_EQ(config_values.c_additional_outputs()[0].AsString(),
             "{{target_out_dir}}/{{source_name_part}}.dwo");
diff --git a/src/gn/filesystem_utils_unittest.cc b/src/gn/filesystem_utils_unittest.cc
index c1a0ae8..7b69a63 100644
--- a/src/gn/filesystem_utils_unittest.cc
+++ b/src/gn/filesystem_utils_unittest.cc
@@ -113,10 +113,10 @@
   err = Err();
   EXPECT_TRUE(
       EnsureStringIsInOutputDir(output_dir, "//out/Debug/", nullptr, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(
       EnsureStringIsInOutputDir(output_dir, "//out/Debug/foo", nullptr, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Pattern but no template expansions are allowed.
   EXPECT_FALSE(EnsureStringIsInOutputDir(output_dir, "{{source_gen_dir}}",
diff --git a/src/gn/function_expand_directory_unittest.cc b/src/gn/function_expand_directory_unittest.cc
index ecd467c..eadcb3e 100644
--- a/src/gn/function_expand_directory_unittest.cc
+++ b/src/gn/function_expand_directory_unittest.cc
@@ -64,7 +64,7 @@
   Value result = functions::RunExpandDirectory(
       setup.scope(), function.get(),
       {Value(nullptr, "//foo/bar"), Value(nullptr, true)}, &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(result.list_value().size(), 3);
@@ -90,7 +90,7 @@
   Value result = functions::RunExpandDirectory(
       setup.scope(), function.get(),
       {Value(nullptr, "bar"), Value(nullptr, false)}, &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(result.list_value().size(), 2);
   EXPECT_EQ(result.list_value()[0].string_value(), "//foo/bar/file1.txt");
@@ -110,7 +110,7 @@
   Value result = functions::RunExpandDirectory(
       setup.scope(), &function, {Value(nullptr, dir_str), Value(nullptr, true)},
       &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(result.list_value().size(), 0);
 }
diff --git a/src/gn/function_filter_labels_unittest.cc b/src/gn/function_filter_labels_unittest.cc
index 4a0ebf3..956bf39 100644
--- a/src/gn/function_filter_labels_unittest.cc
+++ b/src/gn/function_filter_labels_unittest.cc
@@ -26,7 +26,7 @@
   Err err;
   Value result =
       functions::RunFilterLabelsInclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(1u, result.list_value().size());
   ASSERT_TRUE(result.list_value()[0].type() == Value::STRING);
@@ -53,7 +53,7 @@
   Err err;
   Value result =
       functions::RunFilterLabelsInclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(2u, result.list_value().size());
   ASSERT_TRUE(result.list_value()[0].type() == Value::STRING);
@@ -81,7 +81,7 @@
   Err err;
   Value result =
       functions::RunFilterLabelsInclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(0u, result.list_value().size());
 }
@@ -105,7 +105,7 @@
   Err err;
   Value result =
       functions::RunFilterLabelsExclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(1u, result.list_value().size());
   ASSERT_TRUE(result.list_value()[0].type() == Value::STRING);
@@ -132,7 +132,7 @@
   Err err;
   Value result =
       functions::RunFilterLabelsExclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(1u, result.list_value().size());
   ASSERT_TRUE(result.list_value()[0].type() == Value::STRING);
@@ -158,7 +158,7 @@
   Err err;
   Value result =
       functions::RunFilterLabelsExclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(2u, result.list_value().size());
   ASSERT_TRUE(result.list_value()[0].type() == Value::STRING);
diff --git a/src/gn/function_filter_unittest.cc b/src/gn/function_filter_unittest.cc
index 4269f18..1cd5d7e 100644
--- a/src/gn/function_filter_unittest.cc
+++ b/src/gn/function_filter_unittest.cc
@@ -24,7 +24,7 @@
   Err err;
   Value result =
       functions::RunFilterExclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(result.list_value().size(), 2);
   EXPECT_EQ(result.list_value()[0].type(), Value::STRING);
@@ -143,7 +143,7 @@
   Err err;
   Value result =
       functions::RunFilterInclude(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::LIST);
   ASSERT_EQ(result.list_value().size(), 1);
   EXPECT_EQ(result.list_value()[0].type(), Value::STRING);
diff --git a/src/gn/function_foreach_unittest.cc b/src/gn/function_foreach_unittest.cc
index 2093d45..5053649 100644
--- a/src/gn/function_foreach_unittest.cc
+++ b/src/gn/function_foreach_unittest.cc
@@ -15,11 +15,11 @@
       "  a = a + 1\n"  // Test for side effects inside loop.
       "}\n"
       "print(\"$a $i\")");  // Make sure that i goes back to original value.
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("5 1\n6 2\n7 3\n8 6\n", setup.print_output());
 }
@@ -34,7 +34,7 @@
 
   Err err;
   input_good.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("1\n2\n3\n", setup.print_output());
   setup.print_output().clear();
@@ -64,14 +64,14 @@
 
   Err err;
   input_good.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("1\n2\n", setup.print_output());
   setup.print_output().clear();
 
   // Check for unused vars.
   EXPECT_TRUE(setup.scope()->CheckForUnusedVars(&err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 }
 
 // Checks that the list can be modified during iteration without crashing.
@@ -90,7 +90,7 @@
 
   Err err;
   input_grow.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   // The result of the loop should have been unaffected by the mutations of
   // the list variable inside the loop, but the modifications made to it
diff --git a/src/gn/function_forward_variables_from_unittest.cc b/src/gn/function_forward_variables_from_unittest.cc
index 2f60f82..d6a595a 100644
--- a/src/gn/function_forward_variables_from_unittest.cc
+++ b/src/gn/function_forward_variables_from_unittest.cc
@@ -27,10 +27,10 @@
 
     // Defines a template and copy the two x and y, and z values out.
     TestParseInput input(program);
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     input.parsed()->Execute(setup.scope(), &err);
-    ASSERT_FALSE(err.has_error()) << err.message();
+    ASSERT_SUCCESS(err);
 
     EXPECT_EQ("target, 1, 2\n", setup.print_output());
     setup.print_output().clear();
@@ -44,7 +44,7 @@
     // This uses the same known-good program as before, but adds another
     // variable in the scope before it.
     TestParseInput clobber("x = 1\n" + program);
-    ASSERT_FALSE(clobber.has_error());
+    ASSERT_SUCCESS(clobber);
 
     clobber.parsed()->Execute(setup.scope(), &err);
     ASSERT_TRUE(err.has_error());  // Should thow a clobber error.
@@ -63,11 +63,11 @@
       "}\n"
       "print(\"${a.x} ${a.y} ${a.z}\")\n");
 
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("1 2 3\n", setup.print_output());
   setup.print_output().clear();
@@ -90,11 +90,11 @@
       "  print(\"$z\")\n"
       "}\n");
 
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output());
   setup.print_output().clear();
@@ -154,7 +154,7 @@
       "}\n"
       "d(\"target\") {\n"
       "}\n");
-  ASSERT_FALSE(prog.has_error());
+  ASSERT_SUCCESS(prog);
   err = Err();
   prog.parsed()->Execute(setup.scope(), &err);
   EXPECT_TRUE(err.has_error());
@@ -205,11 +205,11 @@
       "  y = 2\n"
       "}\n");
 
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("target, 1, 2\n", setup.print_output());
   setup.print_output().clear();
@@ -233,11 +233,11 @@
       "  print(\"$z\")\n"
       "}\n");
 
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output());
   setup.print_output().clear();
diff --git a/src/gn/function_get_target_outputs_unittest.cc b/src/gn/function_get_target_outputs_unittest.cc
index 4cbd8f9..6a2e86f 100644
--- a/src/gn/function_get_target_outputs_unittest.cc
+++ b/src/gn/function_get_target_outputs_unittest.cc
@@ -69,7 +69,7 @@
 
   Err err;
   Value result = GetTargetOutputs("//foo:bar", &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   AssertSingleStringEquals(result, "//out/Debug/file.txt.one");
 }
 
@@ -84,7 +84,7 @@
 
   Err err;
   Value result = GetTargetOutputs("//foo:bar", &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   AssertTwoStringsEqual(result, "//output1.txt", "//output2.txt");
 }
 
@@ -101,7 +101,7 @@
 
   Err err;
   Value result = GetTargetOutputs("//foo:bar", &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   AssertTwoStringsEqual(result, "//out/Debug/file.txt.one",
                         "//out/Debug/file.txt.two");
 }
diff --git a/src/gn/function_label_matches_unittest.cc b/src/gn/function_label_matches_unittest.cc
index f7bda69..4fa5956 100644
--- a/src/gn/function_label_matches_unittest.cc
+++ b/src/gn/function_label_matches_unittest.cc
@@ -22,7 +22,7 @@
   Err err;
   Value result =
       functions::RunLabelMatches(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::BOOLEAN);
   ASSERT_EQ(result.boolean_value(), true);
 }
@@ -42,7 +42,7 @@
   Err err;
   Value result =
       functions::RunLabelMatches(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::BOOLEAN);
   ASSERT_EQ(result.boolean_value(), true);
 }
@@ -62,7 +62,7 @@
   Err err;
   Value result =
       functions::RunLabelMatches(setup.scope(), &function, args, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(result.type(), Value::BOOLEAN);
   ASSERT_EQ(result.boolean_value(), false);
 }
diff --git a/src/gn/function_len_unittest.cc b/src/gn/function_len_unittest.cc
index 47e3631..16cd160 100644
--- a/src/gn/function_len_unittest.cc
+++ b/src/gn/function_len_unittest.cc
@@ -13,7 +13,7 @@
   std::vector<Value> args;
   args.push_back(Value(nullptr, "foo"));
   Value result = functions::RunLen(setup.scope(), &function_call, args, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.type(), Value::INTEGER);
   EXPECT_EQ(result.int_value(), 3);
 }
@@ -28,7 +28,7 @@
   list_value.list_value().push_back(Value(nullptr, "b"));
   args.push_back(list_value);
   Value result = functions::RunLen(setup.scope(), &function_call, args, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.type(), Value::INTEGER);
   EXPECT_EQ(result.int_value(), 2);
 }
diff --git a/src/gn/function_path_exists_unittest.cc b/src/gn/function_path_exists_unittest.cc
index 402f5dd..fe22857 100644
--- a/src/gn/function_path_exists_unittest.cc
+++ b/src/gn/function_path_exists_unittest.cc
@@ -17,7 +17,7 @@
 
   FunctionCallNode function_call;
   Value result = functions::RunPathExists(scope, &function_call, args, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   return !err.has_error() && result.boolean_value();
 }
 }  // namespace
diff --git a/src/gn/function_process_file_template_unittest.cc b/src/gn/function_process_file_template_unittest.cc
index d9c9919..2966358 100644
--- a/src/gn/function_process_file_template_unittest.cc
+++ b/src/gn/function_process_file_template_unittest.cc
@@ -21,7 +21,7 @@
   Err err;
   Value result =
       functions::RunProcessFileTemplate(setup.scope(), nullptr, args, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   ASSERT_TRUE(result.type() == Value::LIST);
   ASSERT_EQ(1u, result.list_value().size());
@@ -49,7 +49,7 @@
   Err err;
   Value result =
       functions::RunProcessFileTemplate(setup.scope(), nullptr, args, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   ASSERT_TRUE(result.type() == Value::LIST);
   ASSERT_EQ(4u, result.list_value().size());
diff --git a/src/gn/function_rebase_path_unittest.cc b/src/gn/function_rebase_path_unittest.cc
index a4c403f..d587ba9 100644
--- a/src/gn/function_rebase_path_unittest.cc
+++ b/src/gn/function_rebase_path_unittest.cc
@@ -162,7 +162,7 @@
   Err err;
   FunctionCallNode function;
   Value ret = functions::RunRebasePath(setup.scope(), &function, args, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   ASSERT_EQ(Value::LIST, ret.type());
   ASSERT_EQ(2u, ret.list_value().size());
diff --git a/src/gn/function_template_unittest.cc b/src/gn/function_template_unittest.cc
index 2ea9e8b..1d87299 100644
--- a/src/gn/function_template_unittest.cc
+++ b/src/gn/function_template_unittest.cc
@@ -18,12 +18,12 @@
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   // Normally the loader calls CheckForUnusedVars() when it loads a file
   // since normal blocks don't do this check. To avoid having to make this
   // test much more complicated, just explicitly do the check to make sure
   // things are marked properly.
   setup.scope()->CheckForUnusedVars(&err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 }
diff --git a/src/gn/function_toolchain_unittest.cc b/src/gn/function_toolchain_unittest.cc
index 838eb3e..cea95cb 100644
--- a/src/gn/function_toolchain_unittest.cc
+++ b/src/gn/function_toolchain_unittest.cc
@@ -18,7 +18,7 @@
   // Check that creating a toolchain with no name reports an error.
   {
     TestParseInput input(R"(toolchain() {})");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
@@ -28,7 +28,7 @@
   // Check that creating a toolchain with too many arguments is an error.
   {
     TestParseInput input(R"(toolchain("too", "many", "arguments") {})");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
@@ -72,7 +72,7 @@
 
       Err err;
       input.parsed()->Execute(setup.scope(), &err);
-      ASSERT_FALSE(err.has_error()) << err.message();
+      ASSERT_SUCCESS(err);
 
       // It should have generated a toolchain.
       ASSERT_EQ(1u, setup.items().size());
@@ -100,7 +100,7 @@
           })";
       std::string input_str = StrSubstitute(kInput, "{{name}}", tool_type);
       TestParseInput input(input_str);
-      ASSERT_FALSE(input.has_error());
+      ASSERT_SUCCESS(input);
 
       Err err;
       input.parsed()->Execute(setup.scope(), &err);
@@ -154,11 +154,11 @@
             description = "RUST {{output}}"
           }
         })");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
-    ASSERT_FALSE(err.has_error()) << err.message();
+    ASSERT_SUCCESS(err);
 
     // It should have generated a toolchain.
     ASSERT_EQ(1u, setup.items().size());
@@ -189,11 +189,11 @@
             runtime_outputs = [ "stripped" ]
           }
         })");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
-    ASSERT_FALSE(err.has_error()) << err.message();
+    ASSERT_SUCCESS(err);
 
     // It should have generated a toolchain.
     ASSERT_EQ(1u, setup.items().size());
@@ -225,7 +225,7 @@
       R"(toolchain("missing_command") {
         tool("cxx") {}
       })");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -242,11 +242,11 @@
           command_launcher = "/usr/goma/gomacc"
         }
       })");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   // It should have generated a toolchain.
   ASSERT_EQ(1u, setup.items().size());
diff --git a/src/gn/functions_target_rust_unittest.cc b/src/gn/functions_target_rust_unittest.cc
index a8239aa..fcf4060 100644
--- a/src/gn/functions_target_rust_unittest.cc
+++ b/src/gn/functions_target_rust_unittest.cc
@@ -28,7 +28,7 @@
   ASSERT_FALSE(exe_input.has_error());
   Err err;
   exe_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(item_collector.back()->AsTarget()->rust_values().crate_name(),
             "foo_crate");
 
@@ -39,7 +39,7 @@
   ASSERT_FALSE(lib_input.has_error());
   err = Err();
   lib_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(item_collector.back()->AsTarget()->rust_values().crate_name(),
             "foo")
       << item_collector.back()->AsTarget()->rust_values().crate_name();
@@ -62,7 +62,7 @@
   ASSERT_FALSE(normal_input.has_error());
   Err err;
   normal_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(
       item_collector.back()->AsTarget()->rust_values().crate_root().value(),
       "/foo.rs");
@@ -76,7 +76,7 @@
   ASSERT_FALSE(normal_shlib_input.has_error());
   err = Err();
   normal_shlib_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(
       item_collector.back()->AsTarget()->rust_values().crate_root().value(),
       "/foo.rs");
@@ -88,7 +88,7 @@
   ASSERT_FALSE(exe_input.has_error());
   err = Err();
   exe_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(
       item_collector.back()->AsTarget()->rust_values().crate_root().value(),
       "/main.rs");
@@ -100,7 +100,7 @@
   ASSERT_FALSE(lib_input.has_error());
   err = Err();
   lib_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(
       item_collector.back()->AsTarget()->rust_values().crate_root().value(),
       "/lib.rs");
@@ -112,7 +112,7 @@
   ASSERT_FALSE(singlesource_input.has_error());
   err = Err();
   singlesource_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(
       item_collector.back()->AsTarget()->rust_values().crate_root().value(),
       "/bar.rs");
@@ -135,7 +135,7 @@
   ASSERT_FALSE(nosources_input.has_error());
   err = Err();
   nosources_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(
       item_collector.back()->AsTarget()->rust_values().crate_root().value(),
       "/bar.rs");
@@ -158,7 +158,7 @@
   ASSERT_FALSE(lib_input.has_error());
   Err err;
   lib_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(item_collector.back()->AsTarget()->rust_values().crate_type(),
             RustValues::CRATE_DYLIB);
 
@@ -170,7 +170,7 @@
   ASSERT_FALSE(exe_non_default_input.has_error());
   err = Err();
   exe_non_default_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(item_collector.back()->AsTarget()->rust_values().crate_type(),
             RustValues::CRATE_RLIB);
 
@@ -214,7 +214,7 @@
   ASSERT_FALSE(exe_input.has_error());
   Err err;
   exe_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ(item_collector.back()->AsConfig()->own_values().rustflags().size(),
             1U);
@@ -246,7 +246,7 @@
   ASSERT_FALSE(exe_input.has_error());
   Err err;
   exe_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message() << err.message();
+  EXPECT_SUCCESS(err);
 
   EXPECT_EQ(setup.scope()
                 ->GetTargetDefaults("rust_library")
@@ -294,7 +294,7 @@
   ASSERT_FALSE(exe_input.has_error());
   Err err;
   exe_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ(
       item_collector.back()->AsTarget()->rust_values().aliased_deps().size(),
@@ -320,5 +320,5 @@
   ASSERT_FALSE(exe_input.has_error());
   Err err;
   exe_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 }
diff --git a/src/gn/functions_target_unittest.cc b/src/gn/functions_target_unittest.cc
index 04b2a4b..4a397c9 100644
--- a/src/gn/functions_target_unittest.cc
+++ b/src/gn/functions_target_unittest.cc
@@ -25,7 +25,7 @@
   ASSERT_FALSE(good_input.has_error());
   Err err;
   good_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   // Test a source set with an unused variable.
   TestParseInput source_set_input(
@@ -54,7 +54,7 @@
   ASSERT_FALSE(nonscoped_input.has_error());
   Err err;
   nonscoped_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   TestParseInput scoped_input(
       "source_set(\"foo\") {\n"
@@ -64,7 +64,7 @@
   ASSERT_FALSE(scoped_input.has_error());
   err = Err();
   scoped_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   TestParseInput nonexistent_arg_input(
       "source_set(\"foo\") {\n"
@@ -74,7 +74,7 @@
   ASSERT_FALSE(nonexistent_arg_input.has_error());
   err = Err();
   nonexistent_arg_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   TestParseInput exclusion_input(
       "source_set(\"foo\") {\n"
@@ -149,7 +149,7 @@
   ASSERT_FALSE(template_input.has_error());
   err = Err();
   template_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 }
 
 // Checks that the defaults applied to a template invoked by target() use
@@ -182,7 +182,7 @@
   ASSERT_FALSE(good_input.has_error());
   Err err;
   good_input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 }
 
 // Checks that we find unused identifiers in targets.
diff --git a/src/gn/functions_unittest.cc b/src/gn/functions_unittest.cc
index 61a3b35..6fc0e2f 100644
--- a/src/gn/functions_unittest.cc
+++ b/src/gn/functions_unittest.cc
@@ -22,7 +22,7 @@
   };
   for (const auto& assert_pass_example : assert_pass_examples) {
     TestParseInput input(assert_pass_example);
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
     ASSERT_FALSE(err.has_error()) << assert_pass_example;
@@ -31,7 +31,7 @@
   // Verify case where the assertion fails, with no message.
   {
     TestParseInput input("assert(false)");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
     ASSERT_TRUE(err.has_error());
@@ -41,7 +41,7 @@
   // Verify case where the assertion fails, with a message.
   {
     TestParseInput input("assert(false, \"What failed\")");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
     ASSERT_TRUE(err.has_error());
@@ -63,7 +63,7 @@
   };
   for (const auto& bad_usage_example : bad_usage_examples) {
     TestParseInput input(bad_usage_example);
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
     ASSERT_TRUE(err.has_error()) << bad_usage_example;
@@ -142,7 +142,7 @@
   TestParseInput print_no_scope("print(6)");
   EXPECT_FALSE(print_no_scope.has_error());
   Value result = print_no_scope.parsed()->Execute(setup.scope(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Passing a scope should pass parsing (it doesn't know about what kind of
   // function it is) and then throw an error during execution.
@@ -156,7 +156,7 @@
   TestParseInput defined_no_scope("defined(foo)");
   EXPECT_FALSE(defined_no_scope.has_error());
   result = defined_no_scope.parsed()->Execute(setup.scope(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // A block to defined should fail.
   TestParseInput defined_with_scope("defined(foo) {}");
@@ -186,11 +186,11 @@
       // Rounding.
       "out6 = split_list([1, 2, 3, 4, 5, 6], 4)\n"
       "print(\"rounding = $out6\")\n");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ(
       "empty = [[]] [[], [], []]\n"
@@ -211,11 +211,11 @@
         # Empty string
         print("<" + string_hash("") + ">")
         )gn");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
-    ASSERT_FALSE(err.has_error()) << err.message();
+    ASSERT_SUCCESS(err);
 
     EXPECT_EQ(
         "<ba7816bf>\n"
@@ -236,7 +236,7 @@
   };
   for (const auto& bad_usage_example : bad_usage_examples) {
     TestParseInput input(bad_usage_example);
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
@@ -274,11 +274,11 @@
         # Empty string list elements and separator
         print(string_join("", ["", "", ""]))
         )gn");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
-    ASSERT_FALSE(err.has_error()) << err.message();
+    ASSERT_SUCCESS(err);
 
     EXPECT_EQ(
         "<>\n"
@@ -312,7 +312,7 @@
   };
   for (const auto& bad_usage_example : bad_usage_examples) {
     TestParseInput input(bad_usage_example);
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
@@ -339,11 +339,11 @@
       // Handle overlapping occurrences.
       "out4 = string_replace(\"aaa\", \"aa\", \"b\")\n"
       "print(out4)\n");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ(
       "addcc\n"
@@ -393,11 +393,11 @@
         print(string_split(".x.x.x.", ".x."))  # Self-overlapping separators 1
         print(string_split("x.x.x.", ".x."))   # Self-overlapping separators 2
         )gn");
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
 
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
-    ASSERT_FALSE(err.has_error()) << err.message();
+    ASSERT_SUCCESS(err);
 
     EXPECT_EQ(
         // Split on all whitespace: empty string.
@@ -455,7 +455,7 @@
   };
   for (const auto& bad_usage_example : bad_usage_examples) {
     TestParseInput input(bad_usage_example);
-    ASSERT_FALSE(input.has_error());
+    ASSERT_SUCCESS(input);
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
     ASSERT_TRUE(err.has_error()) << bad_usage_example;
@@ -488,7 +488,7 @@
       )");
   err = Err();
   reading_from_outside_call.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
 
   TestParseInput reading_from_different_call(R"(
       declare_args() {
@@ -504,14 +504,14 @@
   err = Err();
   TestWithScope setup2;
   reading_from_different_call.parsed()->Execute(setup2.scope(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
 }
 
 TEST(Functions, NotNeeded) {
   TestWithScope setup;
 
   TestParseInput input("not_needed({ a = 1 }, \"*\")");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -530,11 +530,11 @@
       "foo(\"lala\") {\n"
       "  foo_value = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ(
       "lala\n"
@@ -549,7 +549,7 @@
 TEST(Template, PrintStackTraceWithNoTemplates) {
   TestWithScope setup;
   TestParseInput input("print_stack_trace()\n");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -578,7 +578,7 @@
       "baz(\"lala\") {\n"
       "  bar = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -613,7 +613,7 @@
       "baz(\"lala\") {\n"
       "  bar = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -650,7 +650,7 @@
       "baz(\"lala\") {\n"
       "  bar = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
   ASSERT_FALSE(err.has_error()) << err.message() << "\n\n" << err.help_text();
@@ -692,7 +692,7 @@
       "baz(\"lala\") {\n"
       "  bar = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
   ASSERT_FALSE(err.has_error()) << err.message() << "\n\n" << err.help_text();
diff --git a/src/gn/header_checker_unittest.cc b/src/gn/header_checker_unittest.cc
index ec5a397..99a3606 100644
--- a/src/gn/header_checker_unittest.cc
+++ b/src/gn/header_checker_unittest.cc
@@ -88,7 +88,7 @@
   Target p(setup_.settings(), Label(SourceDir("//p/"), "p"));
   p.set_output_type(Target::SOURCE_SET);
   p.SetToolchain(setup_.toolchain(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   p.private_deps().push_back(LabelTargetPair(&c_));
   p.visibility().SetPublic();
   p.OnResolved(&err);
@@ -318,7 +318,7 @@
 
   Err err;
   s.SetToolchain(setup_.toolchain(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
 
   const SourceFile bridge_header("//bridge.h");
   const SourceFile generated_header("//out/Debug/gen/s/s.h");
@@ -331,7 +331,7 @@
   s.visibility().SetPublic();
 
   s.OnResolved(&err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   targets_.push_back(&s);
 
   auto checker = CreateChecker();
@@ -372,7 +372,7 @@
     include.contents = "lib/header1.h";
     SourceFile source_file = checker->SourceFileForInclude(
         include, kIncludeDirs, dummy_input_file, &err);
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_EQ(SourceFile("//lib/header1.h"), source_file);
   }
 
@@ -382,7 +382,7 @@
     include.contents = "header2.h";
     SourceFile source_file = checker->SourceFileForInclude(
         include, kIncludeDirs, dummy_input_file, &err);
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_EQ(SourceFile("/c/custom_include/header2.h"), source_file);
   }
 
@@ -395,7 +395,7 @@
     include.system_style_include = false;
     SourceFile source_file = checker->SourceFileForInclude(
         include, kIncludeDirs, dummy_input_file, &err);
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_EQ(SourceFile("/d/subdir/header3.h"), source_file);
   }
 
@@ -409,7 +409,7 @@
     SourceFile source_file = checker->SourceFileForInclude(
         include, kIncludeDirs, dummy_input_file, &err);
     EXPECT_TRUE(source_file.is_null());
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
   }
 }
 
@@ -428,7 +428,7 @@
   SourceFile source_file =
       checker->SourceFileForInclude(include, kIncludeDirs, input_file, &err);
   EXPECT_TRUE(source_file.is_null());
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 }
 
 TEST_F(HeaderCheckerTest, Friend) {
@@ -446,7 +446,7 @@
   Err err;
   c_.friends().push_back(LabelPattern::GetPattern(
       SourceDir("//"), std::string_view(), Value(nullptr, "//a:*"), &err));
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
 
   // Must be after setting everything up for it to find the files.
   auto checker = CreateChecker();
diff --git a/src/gn/input_conversion_unittest.cc b/src/gn/input_conversion_unittest.cc
index 054b337..f70a954 100644
--- a/src/gn/input_conversion_unittest.cc
+++ b/src/gn/input_conversion_unittest.cc
@@ -33,14 +33,14 @@
   std::string input("\nfoo bar  \n");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "string"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::STRING, result.type());
   EXPECT_EQ(input, result.string_value());
 
   // Test with trimming.
   result = ConvertInputToValue(settings(), input, nullptr,
                                Value(nullptr, "trim string"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::STRING, result.type());
   EXPECT_EQ("foo bar", result.string_value());
 }
@@ -50,7 +50,7 @@
   std::string input("\nfoo\nbar  \n\n");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "list lines"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::LIST, result.type());
   ASSERT_EQ(4u, result.list_value().size());
   EXPECT_EQ("", result.list_value()[0].string_value());
@@ -61,7 +61,7 @@
   // Test with trimming.
   result = ConvertInputToValue(settings(), input, nullptr,
                                Value(nullptr, "trim list lines"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::LIST, result.type());
   ASSERT_EQ(2u, result.list_value().size());
   EXPECT_EQ("foo", result.list_value()[0].string_value());
@@ -73,7 +73,7 @@
   std::string input("\"str\"");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::STRING, result.type());
   EXPECT_EQ("str", result.string_value());
 }
@@ -83,7 +83,7 @@
   std::string input("\n\n  6 \n ");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::INTEGER, result.type());
   EXPECT_EQ(6, result.int_value());
 }
@@ -93,7 +93,7 @@
   std::string input("\n [ \"a\", 5]");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(Value::LIST, result.type());
   ASSERT_EQ(2u, result.list_value().size());
   EXPECT_EQ("a", result.list_value()[0].string_value());
@@ -105,7 +105,7 @@
   std::string input("\n a = 5 b = \"foo\" c = a + 2");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "scope"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(Value::SCOPE, result.type());
 
   const Value* a_value = result.scope_value()->GetValue("a");
@@ -148,7 +148,7 @@
 })*");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "json"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(Value::SCOPE, result.type());
 
   const Value* a_value = result.scope_value()->GetValue("a");
@@ -229,7 +229,7 @@
   Err err;
   Value result = ConvertInputToValue(settings(), "", nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::NONE, result.type());
 }
 
@@ -265,11 +265,11 @@
 TEST_F(InputConversionTest, Ignore) {
   Err err;
   Value result = ConvertInputToValue(settings(), "foo", nullptr, Value(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::NONE, result.type());
 
   result =
       ConvertInputToValue(settings(), "foo", nullptr, Value(nullptr, ""), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(Value::NONE, result.type());
 }
diff --git a/src/gn/label_pattern_unittest.cc b/src/gn/label_pattern_unittest.cc
index 7ae9f15..a33b49f 100644
--- a/src/gn/label_pattern_unittest.cc
+++ b/src/gn/label_pattern_unittest.cc
@@ -88,7 +88,7 @@
   Err err;
   LabelPattern result = LabelPattern::GetPattern(
       current_dir, source_root, Value(nullptr, "../../../*"), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ(LabelPattern::RECURSIVE_DIRECTORY, result.type());
   EXPECT_EQ("/foo/", result.dir().value()) << result.dir().value();
diff --git a/src/gn/label_unittest.cc b/src/gn/label_unittest.cc
index 5f3bb49..1b545ae 100644
--- a/src/gn/label_unittest.cc
+++ b/src/gn/label_unittest.cc
@@ -107,21 +107,21 @@
   // No source root given, should not go above the root build dir.
   Label result = Label::Resolve(cur_dir, std::string_view(), default_toolchain,
                                 Value(nullptr, "../../..:target"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ("//", result.dir().value()) << result.dir().value();
   EXPECT_EQ("target", result.name());
 
   // Source root provided, it should go into that.
   result = Label::Resolve(cur_dir, source_root, default_toolchain,
                           Value(nullptr, "../../..:target"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ("/foo/", result.dir().value()) << result.dir().value();
   EXPECT_EQ("target", result.name());
 
   // It shouldn't go up higher than the system root.
   result = Label::Resolve(cur_dir, source_root, default_toolchain,
                           Value(nullptr, "../../../../..:target"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ("/", result.dir().value()) << result.dir().value();
   EXPECT_EQ("target", result.name());
 
@@ -131,7 +131,7 @@
   // accident.
   result = Label::Resolve(cur_dir, source_root, default_toolchain,
                           Value(nullptr, "//../.."), &err);
-  EXPECT_FALSE(err.has_error()) << err.message();
+  EXPECT_SUCCESS(err);
   EXPECT_EQ("/foo/", result.dir().value()) << result.dir().value();
   EXPECT_EQ("foo", result.name());
 }
diff --git a/src/gn/loader_unittest.cc b/src/gn/loader_unittest.cc
index dcc5e61..4189315 100644
--- a/src/gn/loader_unittest.cc
+++ b/src/gn/loader_unittest.cc
@@ -129,13 +129,13 @@
   // Tokenize.
   Err err;
   canned->tokens = Tokenizer::Tokenize(canned->input_file.get(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Parse.
   canned->root = Parser::Parse(canned->tokens, &err);
   if (err.has_error())
     err.PrintToStdout();
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   canned_responses_[source_file] = std::move(canned);
 }
diff --git a/src/gn/metadata_unittest.cc b/src/gn/metadata_unittest.cc
index df57cd5..ab14ba6 100644
--- a/src/gn/metadata_unittest.cc
+++ b/src/gn/metadata_unittest.cc
@@ -60,7 +60,7 @@
   EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys,
                                 walk_keys, SourceDir(), &next_walk_keys,
                                 &results, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(next_walk_keys, expected_walk_keys);
   EXPECT_EQ(results, expected);
 }
@@ -94,7 +94,7 @@
   EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys,
                                 walk_keys, SourceDir("/usr/foo_dir/"),
                                 &next_walk_keys, &results, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(next_walk_keys, expected_walk_keys);
   EXPECT_EQ(results, expected);
 }
@@ -148,7 +148,7 @@
   EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys,
                                 walk_keys, SourceDir("/usr/foo_dir/"),
                                 &next_walk_keys, &results, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(next_walk_keys, expected_walk_keys);
   EXPECT_EQ(results, expected);
 }
@@ -177,7 +177,7 @@
   EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys,
                                 walk_keys, SourceDir(), &next_walk_keys,
                                 &results, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(next_walk_keys, expected_walk_keys);
   EXPECT_TRUE(results.empty());
 }
@@ -199,7 +199,7 @@
   EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys,
                                 walk_keys, SourceDir(), &next_walk_keys,
                                 &results, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(next_walk_keys, expected_walk_keys);
   EXPECT_TRUE(results.empty());
 }
@@ -227,7 +227,7 @@
   EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys,
                                 walk_keys, SourceDir(), &next_walk_keys,
                                 &results, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(next_walk_keys, expected_walk_keys);
   EXPECT_TRUE(results.empty());
 }
diff --git a/src/gn/metadata_walk_unittest.cc b/src/gn/metadata_walk_unittest.cc
index 9f83fa3..518fdf2 100644
--- a/src/gn/metadata_walk_unittest.cc
+++ b/src/gn/metadata_walk_unittest.cc
@@ -53,7 +53,7 @@
   TargetSet targets_walked;
   std::vector<Value> result = WalkMetadata(targets, data_keys, walk_keys,
                                            SourceDir(), &targets_walked, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected;
   expected.push_back(Value(nullptr, "foo"));
@@ -103,7 +103,7 @@
   TargetSet targets_walked;
   std::vector<Value> result = WalkMetadata(targets, data_keys, walk_keys,
                                            SourceDir(), &targets_walked, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected;
   expected.push_back(Value(nullptr, "bar"));
@@ -160,7 +160,7 @@
   TargetSet targets_walked;
   std::vector<Value> result = WalkMetadata(targets, data_keys, walk_keys,
                                            SourceDir(), &targets_walked, &err);
-  EXPECT_FALSE(err.has_error()) << err.message();
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected;
   expected.push_back(Value(nullptr, "bar"));
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
index 8d2a84a..14f95ed 100644
--- a/src/gn/ninja_c_binary_target_writer.cc
+++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -462,8 +462,8 @@
               SubstitutionWriter::ApplyPatternToCompilerAsOutputFile(
                   target_, source, pattern);
           if (!extra_output.value().empty() &&
-              std::find(tool_outputs.begin(), tool_outputs.end(), extra_output) ==
-                  tool_outputs.end()) {
+              std::find(tool_outputs.begin(), tool_outputs.end(),
+                        extra_output) == tool_outputs.end()) {
             tool_outputs.push_back(std::move(extra_output));
           }
         }
diff --git a/src/gn/operators_unittest.cc b/src/gn/operators_unittest.cc
index 6420aad..b812aa9 100644
--- a/src/gn/operators_unittest.cc
+++ b/src/gn/operators_unittest.cc
@@ -110,18 +110,18 @@
   // Append an integer.
   node.SetRightToListOfValue(Value(nullptr, static_cast<int64_t>(5)));
   node.Execute(setup.scope(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Append a string that doesn't match the pattern, it should get appended.
   const char string1[] = "good";
   node.SetRightToListOfValue(Value(nullptr, string1));
   node.Execute(setup.scope(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Append a list with the two strings from above.
   node.SetRightToListOfValue(Value(nullptr, string1));
   node.Execute(setup.scope(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // The sources variable in the scope should now have: [ 5, "good", "good" ]
   const Value* value = setup.scope()->GetValue(sources);
@@ -154,7 +154,7 @@
 
   Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
                                     node.right(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Return from the operator should always be "none", it should update the
   // value only.
@@ -205,7 +205,7 @@
   node.SetRightToListOfValue(Value(nullptr, foo_str));
   Value result = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
                                        node.right(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // -= returns an empty value to reduce the possibility of writing confusing
   // cases like foo = bar += 1.
@@ -249,7 +249,7 @@
   node.SetRightToValue(rval);
   Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
                                     node.right(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(Value::LIST, ret.type());
 
   std::vector<Value> expected;
@@ -269,7 +269,7 @@
   node.SetRightToValue(Value(nullptr, static_cast<int64_t>(456)));
   Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
                                     node.right(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(Value::INTEGER, ret.type());
   EXPECT_EQ(579, ret.int_value());
 }
@@ -283,7 +283,7 @@
   node.SetRightToValue(Value(nullptr, static_cast<int64_t>(456)));
   Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
                                     node.right(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   ASSERT_EQ(Value::INTEGER, ret.type());
   EXPECT_EQ(-333, ret.int_value());
 }
@@ -303,7 +303,7 @@
 
   Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
                                     node.right(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 }
 
 TEST(Operators, ShortCircuitOr) {
@@ -321,7 +321,7 @@
 
   Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
                                     node.right(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 }
 
 // Overwriting nonempty lists and scopes with other nonempty lists and scopes
@@ -349,7 +349,7 @@
   // Assigning an empty list should succeed.
   node.SetRightToValue(Value(nullptr, Value::LIST));
   node.Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   const Value* new_value = setup.scope()->GetValue(foo);
   ASSERT_TRUE(new_value);
   ASSERT_EQ(Value::LIST, new_value->type());
@@ -372,7 +372,7 @@
   node.SetRightToValue(
       Value(nullptr, std::make_unique<Scope>(setup.settings())));
   node.Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
   new_value = setup.scope()->GetValue(foo);
   ASSERT_TRUE(new_value);
   ASSERT_EQ(Value::SCOPE, new_value->type());
@@ -403,7 +403,7 @@
   node.SetLeftToIdentifier(foo);
   node.SetRightToValue(Value(nullptr, static_cast<int64_t>(1)));
   node.Execute(&nested, &err);
-  ASSERT_FALSE(err.has_error());
+  ASSERT_SUCCESS(err);
 
   // Outer foo should be used, inner foo should not be.
   EXPECT_FALSE(setup.scope()->IsSetButUnused(foo));
diff --git a/src/gn/output_conversion_unittest.cc b/src/gn/output_conversion_unittest.cc
index 3e1b957..21b9aa0 100644
--- a/src/gn/output_conversion_unittest.cc
+++ b/src/gn/output_conversion_unittest.cc
@@ -42,7 +42,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "list lines"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ("\nfoo\n\nbar\n", result.str());
 }
 
@@ -53,7 +53,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "foo bar");
 }
 
@@ -64,7 +64,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "\"6\"");
 }
 
@@ -75,7 +75,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "\"true\"");
 }
 
@@ -89,7 +89,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "\"[\"foo\", \"bar\", 6]\"");
 }
 
@@ -106,7 +106,7 @@
   std::ostringstream result;
   ConvertValueToOutput(settings(), Value(nullptr, std::move(new_scope)),
                        Value(nullptr, "string"), result, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "\"{\n  _private = \"hello\"\n  v = \"hello\"\n}\"");
 }
 
@@ -117,7 +117,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "\"foo bar\"");
 }
 
@@ -128,7 +128,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "6");
 }
 
@@ -139,7 +139,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "true");
 }
 
@@ -153,7 +153,7 @@
   ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result,
                        &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "[\"foo\", \"bar\", 6]");
 }
 
@@ -170,7 +170,7 @@
   std::ostringstream result;
   ConvertValueToOutput(settings(), Value(nullptr, std::move(new_scope)),
                        Value(nullptr, "value"), result, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "{\n  _private = \"hello\"\n  v = \"hello\"\n}");
 }
 
@@ -216,7 +216,7 @@
   std::ostringstream result;
   ConvertValueToOutput(settings(), Value(nullptr, std::move(new_scope)),
                        Value(nullptr, "json"), result, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), expected);
 }
 
@@ -224,7 +224,7 @@
   Err err;
   std::ostringstream result;
   ConvertValueToOutput(settings(), Value(), Value(nullptr, ""), result, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "<void>");
 }
 
@@ -234,7 +234,7 @@
   std::ostringstream result;
   ConvertValueToOutput(settings(), output, Value(nullptr, ""), result, &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(result.str(), "foo bar");
 }
 
@@ -248,7 +248,7 @@
   std::ostringstream result;
   ConvertValueToOutput(settings(), output, Value(nullptr, ""), result, &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ("\nfoo\n\nbar\n", result.str());
 }
 
@@ -257,12 +257,12 @@
   std::string input("foo bar");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "string"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::ostringstream reverse;
   ConvertValueToOutput(settings(), result, Value(nullptr, "string"), reverse,
                        &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(reverse.str(), input);
 }
 
@@ -271,12 +271,12 @@
   std::string input("\nfoo\nbar\n\n");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "list lines"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::ostringstream reverse;
   ConvertValueToOutput(settings(), result, Value(nullptr, "list lines"),
                        reverse, &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(reverse.str(), input);
 }
 
@@ -285,12 +285,12 @@
   std::string input("\"str\"");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::ostringstream reverse;
   ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse,
                        &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(reverse.str(), input);
 }
 
@@ -299,12 +299,12 @@
   std::string input("6");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::ostringstream reverse;
   ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse,
                        &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(reverse.str(), input);
 }
 
@@ -313,12 +313,12 @@
   std::string input("[\"a\", 5]");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::ostringstream reverse;
   ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse,
                        &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(reverse.str(), input);
 }
 
@@ -327,12 +327,12 @@
   std::string input("  a = 5\n  b = \"foo\"\n  c = 7\n");
   Value result = ConvertInputToValue(settings(), input, nullptr,
                                      Value(nullptr, "scope"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::ostringstream reverse;
   ConvertValueToOutput(settings(), result, Value(nullptr, "scope"), reverse,
                        &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(reverse.str(), input);
 }
 
@@ -340,11 +340,11 @@
   Err err;
   Value result = ConvertInputToValue(settings(), "", nullptr,
                                      Value(nullptr, "value"), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::ostringstream reverse;
   ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse,
                        &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(reverse.str(), "");
 }
diff --git a/src/gn/parse_tree_unittest.cc b/src/gn/parse_tree_unittest.cc
index c5bfa82..49a3fd1 100644
--- a/src/gn/parse_tree_unittest.cc
+++ b/src/gn/parse_tree_unittest.cc
@@ -55,7 +55,7 @@
       ->scope_value()
       ->SetValue("b", Value(nullptr, kBValue), nullptr);
   result = accessor.Execute(setup.scope(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(Value::INTEGER, result.type());
   EXPECT_EQ(kBValue, result.int_value());
 }
@@ -73,29 +73,29 @@
       "second_element_idx = 1");
   values.parsed()->Execute(setup.scope(), &err);
 
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   Value first = setup.ExecuteExpression("list[0]", &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(first.type(), Value::INTEGER);
   EXPECT_EQ(first.int_value(), 2);
 
   Value second = setup.ExecuteExpression("list[second_element_idx]", &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(second.type(), Value::INTEGER);
   EXPECT_EQ(second.int_value(), 3);
 
   const Scope* scope_var = setup.scope()->GetValue("scope")->scope_value();
   EXPECT_TRUE(scope_var->IsSetButUnused("foo"));
   Value foo = setup.ExecuteExpression("scope[\"foo\"]", &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(foo.type(), Value::INTEGER);
   EXPECT_EQ(foo.int_value(), 5);
   EXPECT_FALSE(scope_var->IsSetButUnused("foo"));
 
   EXPECT_TRUE(scope_var->IsSetButUnused("bar"));
   Value bar = setup.ExecuteExpression("scope[bar_key]", &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_EQ(bar.type(), Value::INTEGER);
   EXPECT_EQ(bar.int_value(), 8);
   EXPECT_FALSE(scope_var->IsSetButUnused("bar"));
@@ -136,7 +136,7 @@
 
   Err err;
   input_all_used.parsed()->Execute(setup.scope(), &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Skipping one should throw an unused var error.
   TestParseInput input_unused(
@@ -162,7 +162,7 @@
   TestParseInput input(
       "a = 6\n"
       "get_target_outputs(a)");
-  EXPECT_FALSE(input.has_error());
+  EXPECT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -185,7 +185,7 @@
       "  \"//efg/hij:hij\",\n"
       "  \"//efg/hij:hihihi\",\n"
       "]\n");
-  EXPECT_FALSE(input.has_error());
+  EXPECT_SUCCESS(input);
   ASSERT_TRUE(input.parsed()->AsBlock());
   ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
   const BinaryOpNode* binop =
@@ -246,7 +246,7 @@
         "  \"c\","
         "  \"d\","
         "]\n");
-    EXPECT_FALSE(input.has_error());
+    EXPECT_SUCCESS(input);
     ASSERT_TRUE(input.parsed()->AsBlock());
     ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
     const BinaryOpNode* binop =
@@ -272,7 +272,7 @@
         "  \"c\","
         "  \"d\","
         "]\n");
-    EXPECT_FALSE(input.has_error());
+    EXPECT_SUCCESS(input);
     ASSERT_TRUE(input.parsed()->AsBlock());
     ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
     const BinaryOpNode* binop =
@@ -294,7 +294,7 @@
         "  # At end of list.\n"
         "  \"zzzzzzzzzzz.cc\","
         "]\n");
-    EXPECT_FALSE(input.has_error());
+    EXPECT_SUCCESS(input);
     ASSERT_TRUE(input.parsed()->AsBlock());
     ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
     const BinaryOpNode* binop =
@@ -316,7 +316,7 @@
         "  \"z.cc\","
         "  \"y.cc\","
         "]\n");
-    EXPECT_FALSE(input.has_error());
+    EXPECT_SUCCESS(input);
     ASSERT_TRUE(input.parsed()->AsBlock());
     ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
     const BinaryOpNode* binop =
@@ -341,12 +341,12 @@
   };
   for (auto* s : kGood) {
     TestParseInput input(std::string("x = ") + s);
-    EXPECT_FALSE(input.has_error());
+    EXPECT_SUCCESS(input);
 
     TestWithScope setup;
     Err err;
     input.parsed()->Execute(setup.scope(), &err);
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
   }
 
   static const char* const kBad[] = {
@@ -358,7 +358,7 @@
   };
   for (auto* s : kBad) {
     TestParseInput input(std::string("x = ") + s);
-    EXPECT_FALSE(input.has_error());
+    EXPECT_SUCCESS(input);
 
     TestWithScope setup;
     Err err;
diff --git a/src/gn/scope_unittest.cc b/src/gn/scope_unittest.cc
index c4b966f..4aec54c 100644
--- a/src/gn/scope_unittest.cc
+++ b/src/gn/scope_unittest.cc
@@ -105,7 +105,7 @@
     options.clobber_existing = true;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(&new_scope, options,
                                                    &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
 
     const Value* found_value = new_scope.GetValue("v");
     ASSERT_TRUE(found_value);
@@ -125,7 +125,7 @@
     Err err;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(&new_scope, options,
                                                    &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
 
     const Template* found_value = new_scope.GetTemplate("templ");
     ASSERT_TRUE(found_value);
@@ -141,7 +141,7 @@
     Err err;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
         &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
   }
 
   // Templates that technically collide but are the same.
@@ -155,7 +155,7 @@
     Err err;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
         &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
   }
 
   // Copy private values and templates.
@@ -165,7 +165,7 @@
     Err err;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
         &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_TRUE(new_scope.GetValue(private_var_name));
     EXPECT_TRUE(new_scope.GetTemplate("_templ"));
   }
@@ -179,7 +179,7 @@
     options.skip_private_vars = true;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(&new_scope, options,
                                                    &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_FALSE(new_scope.GetValue(private_var_name));
     EXPECT_FALSE(new_scope.GetTemplate("_templ"));
   }
@@ -192,7 +192,7 @@
     Scope::MergeOptions options;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(&new_scope, options,
                                                    &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_FALSE(new_scope.CheckForUnusedVars(&err));
     EXPECT_TRUE(err.has_error());
   }
@@ -206,9 +206,9 @@
     options.mark_dest_used = true;
     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(&new_scope, options,
                                                    &assignment, "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_TRUE(new_scope.CheckForUnusedVars(&err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
   }
 
   // Build dependency files are merged.
@@ -224,7 +224,7 @@
     Err err;
     EXPECT_TRUE(from_scope.NonRecursiveMergeTo(&to_scope, options, &assignment,
                                                "error", &err));
-    EXPECT_FALSE(err.has_error());
+    EXPECT_SUCCESS(err);
     EXPECT_EQ(1U, to_scope.CollectBuildDependencyFiles().size());
     EXPECT_TRUE(ContainsBuildDependencyFile(&to_scope, source_file));
   }
diff --git a/src/gn/source_dir_unittest.cc b/src/gn/source_dir_unittest.cc
index 148ab92..3623e29 100644
--- a/src/gn/source_dir_unittest.cc
+++ b/src/gn/source_dir_unittest.cc
@@ -38,24 +38,24 @@
   err = Err();
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "//foo"), &err,
                                        source_root) == SourceFile("//foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "/foo"), &err,
                                        source_root) == SourceFile("/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Basic relative stuff.
   EXPECT_TRUE(
       base.ResolveRelativeFile(Value(nullptr, "foo"), &err, source_root) ==
       SourceFile("//base/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(
       base.ResolveRelativeFile(Value(nullptr, "./foo"), &err, source_root) ==
       SourceFile("//base/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "../foo"), &err,
                                        source_root) == SourceFile("//foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
 // If the given relative path points outside the source root, we
 // expect an absolute path.
@@ -63,42 +63,42 @@
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "../../foo"), &err,
                                        source_root) ==
               SourceFile("/C:/source/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EXPECT_TRUE(
       base.ResolveRelativeFile(Value(nullptr, "//../foo"), &err, source_root) ==
       SourceFile("/C:/source/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "//../root/foo"), &err,
                                        source_root) ==
               SourceFile("/C:/source/root/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "//../../../foo/bar"),
                                        &err,
                                        source_root) == SourceFile("/foo/bar"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 #else
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "../../foo"), &err,
                                        source_root) ==
               SourceFile("/source/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EXPECT_TRUE(
       base.ResolveRelativeFile(Value(nullptr, "//../foo"), &err, source_root) ==
       SourceFile("/source/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "//../root/foo"), &err,
                                        source_root) ==
               SourceFile("/source/root/foo"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "//../../../foo/bar"),
                                        &err,
                                        source_root) == SourceFile("/foo/bar"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 #endif
 
 #if defined(OS_WIN)
@@ -108,7 +108,7 @@
   EXPECT_TRUE(base.ResolveRelativeFile(Value(nullptr, "C:\\foo\\bar.txt"), &err,
                                        source_root) ==
               SourceFile("/C:/foo/bar.txt"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 #endif
 }
 
@@ -130,21 +130,21 @@
   err = Err();
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "//foo"), &err,
                                       source_root) == SourceDir("//foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "/foo"), &err,
                                       source_root) == SourceDir("/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   // Basic relative stuff.
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "foo"), &err,
                                       source_root) == SourceDir("//base/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "./foo"), &err,
                                       source_root) == SourceDir("//base/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "../foo"), &err,
                                       source_root) == SourceDir("//foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
 // If the given relative path points outside the source root, we
 // expect an absolute path.
@@ -152,26 +152,26 @@
   EXPECT_TRUE(
       base.ResolveRelativeDir(Value(nullptr, "../../foo"), &err, source_root) ==
       SourceDir("/C:/source/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(
       base.ResolveRelativeDir(Value(nullptr, "//../foo"), &err, source_root) ==
       SourceDir("/C:/source/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "//.."), &err,
                                       source_root) == SourceDir("/C:/source/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 #else
   EXPECT_TRUE(
       base.ResolveRelativeDir(Value(nullptr, "../../foo"), &err, source_root) ==
       SourceDir("/source/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(
       base.ResolveRelativeDir(Value(nullptr, "//../foo"), &err, source_root) ==
       SourceDir("/source/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "//.."), &err,
                                       source_root) == SourceDir("/source/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 #endif
 
 #if defined(OS_WIN)
@@ -179,10 +179,10 @@
   // leading slash if necessary.
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "\\C:\\foo"), &err) ==
               SourceDir("/C:/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   EXPECT_TRUE(base.ResolveRelativeDir(Value(nullptr, "C:\\foo"), &err) ==
               SourceDir("/C:/foo/"));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 #endif
 }
 
diff --git a/src/gn/substitution_pattern_unittest.cc b/src/gn/substitution_pattern_unittest.cc
index 76e4dec..71ecfbb 100644
--- a/src/gn/substitution_pattern_unittest.cc
+++ b/src/gn/substitution_pattern_unittest.cc
@@ -12,7 +12,7 @@
   SubstitutionPattern pattern;
   Err err;
   EXPECT_TRUE(pattern.Parse("This is a literal", nullptr, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(1u, pattern.ranges().size());
   EXPECT_EQ(&SubstitutionLiteral, pattern.ranges()[0].type);
   EXPECT_EQ("This is a literal", pattern.ranges()[0].literal);
@@ -23,7 +23,7 @@
   Err err;
   EXPECT_TRUE(pattern.Parse(
       "AA{{source}}{{source_name_part}}BB{{source_file_part}}", nullptr, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(5u, pattern.ranges().size());
 
   EXPECT_EQ(&SubstitutionLiteral, pattern.ranges()[0].type);
@@ -56,7 +56,7 @@
   EXPECT_TRUE(pattern.Parse(
       "AA{{rustflags}}{{rustenv}}BB{{crate_name}}{{rustdeps}}CC{{externs}}",
       nullptr, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(8u, pattern.ranges().size());
 
   EXPECT_EQ(&SubstitutionLiteral, pattern.ranges()[0].type);
diff --git a/src/gn/substitution_writer_unittest.cc b/src/gn/substitution_writer_unittest.cc
index eaa521a..5ea595e 100644
--- a/src/gn/substitution_writer_unittest.cc
+++ b/src/gn/substitution_writer_unittest.cc
@@ -95,7 +95,7 @@
   SubstitutionPattern pattern;
   ASSERT_TRUE(pattern.Parse("-i {{source}} --out=bar\"{{source_name_part}}\".o",
                             nullptr, &err));
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   EscapeOptions options;
   options.mode = ESCAPE_NONE;
diff --git a/src/gn/target_unittest.cc b/src/gn/target_unittest.cc
index b920c26..81c93ef 100644
--- a/src/gn/target_unittest.cc
+++ b/src/gn/target_unittest.cc
@@ -1282,7 +1282,7 @@
   TargetSet targets;
   one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
                   &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected;
   expected.push_back(Value(nullptr, "foo"));
@@ -1323,7 +1323,7 @@
   TargetSet targets;
   one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
                   &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected;
   expected.push_back(Value(nullptr, "bar"));
@@ -1370,7 +1370,7 @@
   TargetSet targets;
   one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
                   &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected;
   expected.push_back(Value(nullptr, "bar"));
@@ -1419,7 +1419,7 @@
   TargetSet targets;
   one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
                   &err);
-  EXPECT_FALSE(err.has_error()) << err.message();
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected;
   expected.push_back(Value(nullptr, "bar"));
@@ -1561,7 +1561,7 @@
   Err err;
   a.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
                 &err);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
 
   std::vector<Value> expected = {Value(nullptr, "bar"), Value(nullptr, "foo")};
   EXPECT_EQ(result, expected);
diff --git a/src/gn/template_unittest.cc b/src/gn/template_unittest.cc
index a8c88dc..58dbf66 100644
--- a/src/gn/template_unittest.cc
+++ b/src/gn/template_unittest.cc
@@ -16,11 +16,11 @@
       "foo(\"lala\") {\n"
       "  bar = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(err.has_error()) << err.message();
+  ASSERT_SUCCESS(err);
 
   EXPECT_EQ("lala\n42\n", setup.print_output());
 }
@@ -34,7 +34,7 @@
       "foo(\"lala\") {\n"
       "  bar = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -50,7 +50,7 @@
       "foo(\"lala\") {\n"
       "  bar = 42\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -68,7 +68,7 @@
       "  bar = 42\n"
       "  baz = [ \"foo\" ]\n"
       "}");
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
@@ -89,5 +89,5 @@
 
   Err err;
   input.parsed()->Execute(setup.scope(), &err);
-  ASSERT_FALSE(input.has_error());
+  ASSERT_SUCCESS(input);
 }
diff --git a/src/gn/test_with_scope.h b/src/gn/test_with_scope.h
index 14881a8..38f7ec0 100644
--- a/src/gn/test_with_scope.h
+++ b/src/gn/test_with_scope.h
@@ -98,6 +98,7 @@
   // Indicates whether and what error occurred during tokenizing and parsing.
   bool has_error() const { return parse_err_.has_error(); }
   const Err& parse_err() const { return parse_err_; }
+  const std::string& message() const { return parse_err_.message(); }
 
   const InputFile& input_file() const { return input_file_; }
   const std::vector<Token>& tokens() const { return tokens_; }
diff --git a/src/gn/tokenizer_unittest.cc b/src/gn/tokenizer_unittest.cc
index dfec895..6f6f0e0 100644
--- a/src/gn/tokenizer_unittest.cc
+++ b/src/gn/tokenizer_unittest.cc
@@ -234,7 +234,7 @@
   Err err;
   std::vector<Token> results =
       Tokenizer::Tokenize(&input, &err, WhitespaceTransform::kInvalidToSpace);
-  EXPECT_FALSE(err.has_error());
+  EXPECT_SUCCESS(err);
   ASSERT_EQ(results.size(), 4u);
   EXPECT_EQ(results[0].type(), Token::IDENTIFIER);
   EXPECT_EQ(results[0].value(), "a");
diff --git a/src/util/test/test.h b/src/util/test/test.h
index 2419963..94d7129 100644
--- a/src/util/test/test.h
+++ b/src/util/test/test.h
@@ -217,4 +217,22 @@
   TEST_ASSERT_(::testing::TestResult(strcmp(a, b) == 0, #a " str== " #b), \
                TEST_FATAL_FAILURE_)
 
+#define EXPECT_SUCCESS(err)                                       \
+  TEST_AMBIGUOUS_ELSE_BLOCKER_                                    \
+  if (const auto& test_err = (err); !test_err.has_error())        \
+    ;                                                             \
+  else                                                            \
+    TEST_NONFATAL_FAILURE_(                                       \
+        ::testing::TestResult(false, "EXPECT_SUCCESS(" #err ")")) \
+        << test_err.message()
+
+#define ASSERT_SUCCESS(err)                                       \
+  TEST_AMBIGUOUS_ELSE_BLOCKER_                                    \
+  if (const auto& test_err = (err); !test_err.has_error())        \
+    ;                                                             \
+  else                                                            \
+    TEST_FATAL_FAILURE_(                                          \
+        ::testing::TestResult(false, "ASSERT_SUCCESS(" #err ")")) \
+        << test_err.message()
+
 #endif  // UTIL_TEST_TEST_H_