Refactor csv_reader_unittest.cc

The file was a long collection of two types of test: successful and
failing parsing of a CSV. Within each TEST macro, boilerplate was
repeated. Through copy-paste errors ASSERT_FALSE were used where
EXPECT_FALSE were more appropriate.

This CL modifies the file so that it only has two TEST instances, one
for all the positive and one for negative cases. The particular inputs
and expectations are wrapped in test-case structs, where the test
values are not lost among boilerplate. Copy-paste errors are limited
because there is not much to copy-paste anymore when adding a new
test.

Bug: 921383
Change-Id: I124adaac97f1986549d4766209db6564a92126b4
Reviewed-on: https://chromium-review.googlesource.com/c/1415297
Commit-Queue: Vaclav Brozek <vabr@chromium.org>
Reviewed-by: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#623814}
diff --git a/components/password_manager/core/browser/import/csv_reader_unittest.cc b/components/password_manager/core/browser/import/csv_reader_unittest.cc
index c0a79a08..5fc23a5 100644
--- a/components/password_manager/core/browser/import/csv_reader_unittest.cc
+++ b/components/password_manager/core/browser/import/csv_reader_unittest.cc
@@ -4,328 +4,217 @@
 
 #include "components/password_manager/core/browser/import/csv_reader.h"
 
+#include <utility>
+#include <vector>
+
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace password_manager {
 
-TEST(CSVReaderTest, EmptyCSV) {
-  CSVTable table;
-  EXPECT_TRUE(table.ReadCSV(std::string()));
-  EXPECT_THAT(table.column_names(), testing::ElementsAre(""));
-  EXPECT_EQ(0u, table.records().size());
+TEST(CSVReaderTest, Positive) {
+  struct TestCase {
+    const char* name;
+    const char* input;
+    std::vector<const char*> expected_column_names;
+    std::vector<std::vector<std::pair<const char*, const char*>>>
+        expected_row_maps;
+  };
+  const TestCase kCases[] = {
+      {
+          "EmptyCSV",
+          "",
+          {""},
+          {},
+      },
+      {
+          "CSVConsistingOfSingleNewLine",
+          "\n",
+          {""},
+          {},
+      },
+      {
+          "SingleColumn",
+          "foo\n"
+          "alpha\n"
+          "beta\n",
+          {"foo"},
+          {{{"foo", "alpha"}}, {{"foo", "beta"}}},
+      },
+      {
+          "HeaderOnly",
+          "foo,bar\n",
+          {"foo", "bar"},
+          {},
+      },
+      {
+          "NoNewline",
+          "foo,bar",
+          {"foo", "bar"},
+          {},
+      },
+      {
+          "HeaderAndSimpleRecords",
+          "foo,bar,baz\n"
+          "alpha,beta,gamma\n"
+          "delta,epsilon,zeta\n",
+          {"foo", "bar", "baz"},
+          {{{"bar", "beta"}, {"baz", "gamma"}, {"foo", "alpha"}},
+           {{"bar", "epsilon"}, {"baz", "zeta"}, {"foo", "delta"}}},
+      },
+      {
+          "EmptyStringColumnNamesAreSupported",
+          "foo,,bar\n"
+          "alpha,beta,gamma\n",
+          {"foo", "", "bar"},
+          {{{"", "beta"}, {"bar", "gamma"}, {"foo", "alpha"}}},
+      },
+      {
+          "ExtraSpacesArePreserved",
+          "left,right\n"
+          " alpha  beta ,  \n",
+          {"left", "right"},
+          {{{"left", " alpha  beta "}, {"right", "  "}}},
+      },
+      {
+          "CharactersOutsideASCIIPrintableArePreservedVerbatim",
+          "left,right\n"
+          "\x07\t\x0B\x1F,$\xc2\xa2\xe2\x98\x83\xf0\xa4\xad\xa2\n",
+          {"left", "right"},
+          {{// Characters below 0x20: bell, horizontal + vertical tab, unit
+            // separator.
+            {"left", "\x07\t\x0B\x1F"},
+            // Unicode code points having 1..4 byte UTF-8 representation: dollar
+            // sign (U+0024), cent sign (U+00A2), snowman (U+2603), Han
+            // character U+24B62.
+            {"right", "$\xc2\xa2\xe2\x98\x83\xf0\xa4\xad\xa2"}}},
+      },
+      {
+          "EnclosingDoubleQuotesAreTrimmed",
+          "\"left\",\"right\"\n"
+          "\"alpha\",\"beta\"\n",
+          {"left", "right"},
+          {{{"left", "alpha"}, {"right", "beta"}}},
+      },
+      {
+          "SeparatorsInsideDoubleQuotesAreTreatedVerbatim",
+          "left,right\n"
+          "\"A\rB\",\"B\nC\"\n"
+          "\"C\r\nD\",\"D\n\"\n"
+          "\",\",\",,\"\n",
+          {"left", "right"},
+          {{{"left", "A\rB"}, {"right", "B\nC"}},
+           {{"left", "C\nD"}, {"right", "D\n"}},
+           {{"left", ","}, {"right", ",,"}}},
+      },
+      {
+          "EscapedDoubleQuotes",
+          "left,right\n"
+          R"("","""""")"
+          "\n"
+          R"("""","A""B""""C")"
+          "\n",
+          {"left", "right"},
+          {{{"left", ""}, {"right", "\"\""}},
+           {{"left", "\""}, {"right", "A\"B\"\"C"}}},
+      },
+      {
+          "InconsistentFieldsCountIsTreatedGracefully",
+          "left,right\n"
+          "A\n"
+          "B,C,D\n",
+          {"left", "right"},
+          {{{"left", "A"}}, {{"left", "B"}, {"right", "C"}}},
+      },
+      {
+          "SupportMissingNewLineAtEOF",
+          "left,right\n"
+          "alpha,beta",
+          {"left", "right"},
+          {{{"left", "alpha"}, {"right", "beta"}}},
+      },
+      {
+          "EmptyFields",
+          "left,middle,right\n"
+          "alpha,beta,\n"
+          ",,gamma\n",
+          {"left", "middle", "right"},
+          {{{"left", "alpha"}, {"middle", "beta"}, {"right", ""}},
+           {{"left", ""}, {"middle", ""}, {"right", "gamma"}}},
+      },
+      {
+          "CRLFTreatedAsAndConvertedToLF",
+          "left,right\r\n"
+          "\"\r\",\"\r\n\"\r\n",
+          {"left", "right"},
+          {{{"left", "\r"}, {"right", "\n"}}},
+      },
+      {
+          "LastValueForRepeatedColumnNamesIsPreserved",
+          "foo,bar,bar\n"
+          "alpha,beta,gamma\n",
+          {"foo", "bar", "bar"},
+          {{{"bar", "gamma"}, {"foo", "alpha"}}},
+      },
+      {
+          "EmptyLastFieldAndNoNewline",
+          "alpha,",
+          {"alpha", ""},
+          {},
+      },
+  };
+
+  for (const TestCase& test_case : kCases) {
+    SCOPED_TRACE(test_case.name);
+    CSVTable table;
+    ASSERT_TRUE(table.ReadCSV(test_case.input));
+
+    EXPECT_THAT(table.column_names(),
+                testing::ElementsAreArray(test_case.expected_column_names));
+    ASSERT_EQ(test_case.expected_row_maps.size(), table.records().size());
+    for (size_t i = 0; i < test_case.expected_row_maps.size(); ++i) {
+      EXPECT_THAT(table.records()[i],
+                  testing::ElementsAreArray(test_case.expected_row_maps[i]));
+    }
+  }
 }
 
-TEST(CSVReaderTest, CSVConsistingOfSingleNewLine) {
-  CSVTable table;
-  EXPECT_TRUE(table.ReadCSV(std::string("\n")));
-  EXPECT_THAT(table.column_names(), testing::ElementsAre(""));
-  EXPECT_EQ(0u, table.records().size());
-}
+TEST(CSVReaderTest, Negative) {
+  struct TestCase {
+    const char* name;
+    const char* input;
+  };
+  const TestCase kCases[] = {
+      {
+          "FailureWhenEOFInsideQuotes",
+          "left,right\n"
+          "\"alpha\",\"unmatched\n",
+      },
+      {
+          "FailureWhenSemiQuotedContentInHeader",
+          "\"a\"b\"c\",right\n"
+          "alpha,beta\n",
+      },
+      {
+          "FailureWhenSemiQuotedContentOnSubsequentLine",
+          "alpha,beta\n"
+          "left,\"a\"b\"c\"\n",
+      },
+      {
+          "FailureWhenJustOneQuote",
+          "\"",
+      },
+      {
+          "FailureWhenJustOneQuoteAndComma",
+          "\",",
+      },
+  };
 
-TEST(CSVReaderTest, SingleColumn) {
-  const char kTestCSVInput[] =
-      "foo\n"
-      "alpha\n"
-      "beta\n";
-
-  CSVTable table;
-  EXPECT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("foo"));
-  ASSERT_EQ(2u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("foo", "alpha")));
-  EXPECT_THAT(table.records()[1],
-              testing::ElementsAre(std::make_pair("foo", "beta")));
-}
-
-TEST(CSVReaderTest, HeaderOnly) {
-  const char kTestCSVInput[] =
-      "foo,bar\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("foo", "bar"));
-  EXPECT_EQ(0u, table.records().size());
-}
-
-TEST(CSVReaderTest, NoNewline) {
-  const char kTestCSVInput[] = "foo,bar";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("foo", "bar"));
-  EXPECT_EQ(0u, table.records().size());
-}
-
-TEST(CSVReaderTest, HeaderAndSimpleRecords) {
-  const char kTestCSVInput[] =
-      "foo,bar,baz\n"
-      "alpha,beta,gamma\n"
-      "delta,epsilon,zeta\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("foo", "bar", "baz"));
-  ASSERT_EQ(2u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("bar", "beta"),
-                                   std::make_pair("baz", "gamma"),
-                                   std::make_pair("foo", "alpha")));
-  EXPECT_THAT(table.records()[1],
-              testing::ElementsAre(std::make_pair("bar", "epsilon"),
-                                   std::make_pair("baz", "zeta"),
-                                   std::make_pair("foo", "delta")));
-}
-
-TEST(CSVReaderTest, EmptyStringColumnNamesAreSupported) {
-  const char kTestCSVInput[] =
-      "foo,,bar\n"
-      "alpha,beta,gamma\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("foo", "", "bar"));
-  ASSERT_EQ(1u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("", "beta"),
-                                   std::make_pair("bar", "gamma"),
-                                   std::make_pair("foo", "alpha")));
-}
-
-TEST(CSVReaderTest, ExtraSpacesArePreserved) {
-  const char kTestCSVInput[] =
-      "left,right\n"
-      " alpha  beta ,  \n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(1u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", " alpha  beta "),
-                                   std::make_pair("right", "  ")));
-}
-
-TEST(CSVReaderTest, CharactersOutsideASCIIPrintableArePreservedVerbatim) {
-  const char kTestCSVInput[] =
-      "left,right\n"
-      "\x07\t\x0B\x1F,$\xc2\xa2\xe2\x98\x83\xf0\xa4\xad\xa2\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(1u, table.records().size());
-  EXPECT_THAT(
-      table.records()[0],
-      testing::ElementsAre(
-          // Characters below 0x20: bell, horizontal + vertical tab, unit
-          // separator.
-          std::make_pair("left", "\x07\t\x0B\x1F"),
-          // Unicode code points having 1..4 byte UTF-8 representation: dollar
-          // sign (U+0024), cent sign (U+00A2), snowman (U+2603), Han character
-          // U+24B62.
-          std::make_pair("right", "$\xc2\xa2\xe2\x98\x83\xf0\xa4\xad\xa2")));
-}
-
-TEST(CSVReaderTest, EnclosingDoubleQuotesAreTrimmed) {
-  const char kTestCSVInput[] =
-      "\"left\",\"right\"\n"
-      "\"alpha\",\"beta\"\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(1u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", "alpha"),
-                                   std::make_pair("right", "beta")));
-}
-
-TEST(CSVReaderTest, SeparatorsInsideDoubleQuotesAreTreatedVerbatim) {
-  const char kTestCSVInput[] =
-      "left,right\n"
-      "\"A\rB\",\"B\nC\"\n"
-      "\"C\r\nD\",\"D\n\"\n"
-      "\",\",\",,\"\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(3u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", "A\rB"),
-                                   std::make_pair("right", "B\nC")));
-  EXPECT_THAT(table.records()[1],
-              testing::ElementsAre(std::make_pair("left", "C\nD"),
-                                   std::make_pair("right", "D\n")));
-  EXPECT_THAT(table.records()[2],
-              testing::ElementsAre(std::make_pair("left", ","),
-                                   std::make_pair("right", ",,")));
-}
-
-TEST(CSVReaderTest, EscapedDoubleQuotes) {
-  const char kTestCSVInput[] =
-      "left,right\n"
-      "\"\",\"\"\"\"\"\"\n"
-      "\"\"\"\",\"A\"\"B\"\"\"\"C\"\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(2u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", ""),
-                                   std::make_pair("right", "\"\"")));
-  EXPECT_THAT(table.records()[1],
-              testing::ElementsAre(std::make_pair("left", "\""),
-                                   std::make_pair("right", "A\"B\"\"C")));
-}
-
-TEST(CSVReaderTest, InconsistentFieldsCountIsTreatedGracefully) {
-  const char kTestCSVInput[] =
-      "left,right\n"
-      "A\n"
-      "B,C,D\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(2u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", "A")));
-  EXPECT_THAT(table.records()[1],
-              testing::ElementsAre(std::make_pair("left", "B"),
-                                   std::make_pair("right", "C")));
-}
-
-TEST(CSVReaderTest, SupportMissingNewLineAtEOF) {
-  const char kTestCSVInput[] =
-      "left,right\n"
-      "alpha,beta";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(1u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", "alpha"),
-                                   std::make_pair("right", "beta")));
-}
-
-TEST(CSVReaderTest, EmptyFields) {
-  const char kTestCSVInput[] =
-      "left,middle,right\n"
-      "alpha,beta,\n"
-      ",,gamma\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(),
-              testing::ElementsAre("left", "middle", "right"));
-  ASSERT_EQ(2u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", "alpha"),
-                                   std::make_pair("middle", "beta"),
-                                   std::make_pair("right", "")));
-  EXPECT_THAT(table.records()[1],
-              testing::ElementsAre(std::make_pair("left", ""),
-                                   std::make_pair("middle", ""),
-                                   std::make_pair("right", "gamma")));
-}
-
-TEST(CSVReaderTest, CRLFTreatedAsAndConvertedToLF) {
-  const char kTestCSVInput[] =
-      "left,right\r\n"
-      "\"\r\",\"\r\n\"\r\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("left", "right"));
-  ASSERT_EQ(1u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("left", "\r"),
-                                   std::make_pair("right", "\n")));
-}
-
-TEST(CSVReaderTest, LastValueForRepeatedColumnNamesIsPreserved) {
-  const char kTestCSVInput[] =
-      "foo,bar,bar\n"
-      "alpha,beta,gamma\n";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("foo", "bar", "bar"));
-  ASSERT_EQ(1u, table.records().size());
-  EXPECT_THAT(table.records()[0],
-              testing::ElementsAre(std::make_pair("bar", "gamma"),
-                                   std::make_pair("foo", "alpha")));
-}
-
-TEST(CSVReaderTest, FailureWhenEOFInsideQuotes) {
-  const char kTestCSVInput[] =
-      "left,right\n"
-      "\"alpha\",\"unmatched\n";
-
-  CSVTable table;
-  ASSERT_FALSE(table.ReadCSV(kTestCSVInput));
-}
-
-TEST(CSVReaderTest, FailureWhenSemiQuotedContentInHeader) {
-  const char kTestCSVInput[] =
-      "\"a\"b\"c\",right\n"
-      "alpha,beta\n";
-
-  CSVTable table;
-  ASSERT_FALSE(table.ReadCSV(kTestCSVInput));
-}
-
-TEST(CSVReaderTest, FailureWhenSemiQuotedContentOnSubsequentLine) {
-  const char kTestCSVInput[] =
-      "alpha,beta\n"
-      "left,\"a\"b\"c\"\n";
-
-  CSVTable table;
-  ASSERT_FALSE(table.ReadCSV(kTestCSVInput));
-}
-
-TEST(CSVReaderTest, FailureWhenJustOneQuote) {
-  const char kTestCSVInput[] = "\"";
-
-  CSVTable table;
-  EXPECT_FALSE(table.ReadCSV(kTestCSVInput));
-}
-
-TEST(CSVReaderTest, FailureWhenJustOneQuoteAndComma) {
-  const char kTestCSVInput[] = "\",";
-
-  CSVTable table;
-  EXPECT_FALSE(table.ReadCSV(kTestCSVInput));
-}
-
-TEST(CSVReaderTest, EmptyLastFieldAndNoNewline) {
-  const char kTestCSVInput[] = "alpha,";
-
-  CSVTable table;
-  ASSERT_TRUE(table.ReadCSV(kTestCSVInput));
-
-  EXPECT_THAT(table.column_names(), testing::ElementsAre("alpha", ""));
-  ASSERT_TRUE(table.records().empty());
+  for (const TestCase& test_case : kCases) {
+    SCOPED_TRACE(test_case.name);
+    CSVTable table;
+    EXPECT_FALSE(table.ReadCSV(test_case.input));
+  }
 }
 
 }  // namespace password_manager