Parcourir la source

Add remaining tests to Xcode (#1256)

* Add classes in testutil and util to the project

  * Exclude util/iterator_adaptors_test which requires gmock
  * Exclude remote/serializer_test which is missing some paths

* Add iterator_adaptors_test and add gmock support

  * Add gmock support to the GoogleTest podspec we vendor
  * Add iterator_adaptors_test.cc to the Xcode project

* Add a script that verifies all tests are referenced in the project

* Add a travis check that all tests are referenced in the project

* Review feedback

* Moar feedback
Gil il y a 8 ans
Parent
commit
602c262c6b

+ 1 - 0
.travis.yml

@@ -18,6 +18,7 @@ jobs:
         - ./scripts/check_whitespace.sh
         - ./scripts/check_copyright.sh
         - ./scripts/check_no_module_imports.sh
+        - ./scripts/check_test_inclusion.py
         - ./scripts/style.sh test-only $TRAVIS_COMMIT_RANGE
         # Google C++ style compliance
         - ./scripts/lint.sh $TRAVIS_COMMIT_RANGE

+ 24 - 2
Firestore/Example/Firestore.xcodeproj/project.pbxproj

@@ -118,6 +118,10 @@
 		549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA5520A36E1F00BCEB75 /* precondition_test.cc */; };
 		54A0352620A3AED0003E0143 /* field_transform_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352320A3AEC3003E0143 /* field_transform_test.mm */; };
 		54A0352720A3AED0003E0143 /* transform_operations_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352220A3AEC3003E0143 /* transform_operations_test.mm */; };
+		54A0352A20A3B3BD003E0143 /* testutil.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352820A3B3BD003E0143 /* testutil.cc */; };
+		54A0352F20A3B3D8003E0143 /* status_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352C20A3B3D7003E0143 /* status_test.cc */; };
+		54A0353020A3B3D8003E0143 /* statusor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352D20A3B3D7003E0143 /* statusor_test.cc */; };
+		54A0353520A3D8CB003E0143 /* iterator_adaptors_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */; };
 		54C2294F1FECABAE007D065B /* log_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54C2294E1FECABAE007D065B /* log_test.cc */; };
 		54DA12A61F315EE100DD57A1 /* collection_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129C1F315EE100DD57A1 /* collection_spec_test.json */; };
 		54DA12A71F315EE100DD57A1 /* existence_filter_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129D1F315EE100DD57A1 /* existence_filter_spec_test.json */; };
@@ -353,6 +357,12 @@
 		549CCA5520A36E1F00BCEB75 /* precondition_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = precondition_test.cc; sourceTree = "<group>"; };
 		54A0352220A3AEC3003E0143 /* transform_operations_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = transform_operations_test.mm; sourceTree = "<group>"; };
 		54A0352320A3AEC3003E0143 /* field_transform_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = field_transform_test.mm; sourceTree = "<group>"; };
+		54A0352820A3B3BD003E0143 /* testutil.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testutil.cc; sourceTree = "<group>"; };
+		54A0352920A3B3BD003E0143 /* testutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testutil.h; sourceTree = "<group>"; };
+		54A0352B20A3B3D7003E0143 /* status_test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status_test_util.h; sourceTree = "<group>"; };
+		54A0352C20A3B3D7003E0143 /* status_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status_test.cc; sourceTree = "<group>"; };
+		54A0352D20A3B3D7003E0143 /* statusor_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statusor_test.cc; sourceTree = "<group>"; };
+		54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iterator_adaptors_test.cc; sourceTree = "<group>"; };
 		54C2294E1FECABAE007D065B /* log_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log_test.cc; sourceTree = "<group>"; };
 		54C9EDF12040E16300A969CD /* Firestore_SwiftTests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_SwiftTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		54C9EDF52040E16300A969CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -519,6 +529,8 @@
 			children = (
 				5467FB06203E6A44009C9584 /* app_testing.h */,
 				5467FB07203E6A44009C9584 /* app_testing.mm */,
+				54A0352820A3B3BD003E0143 /* testutil.cc */,
+				54A0352920A3B3BD003E0143 /* testutil.h */,
 			);
 			path = testutil;
 			sourceTree = "<group>";
@@ -548,9 +560,13 @@
 				B6FB4688208F9B9100554BA2 /* executor_test.cc */,
 				B6FB468A208F9B9100554BA2 /* executor_test.h */,
 				54511E8D209805F8005BD28F /* hashing_test.cc */,
+				54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */,
 				54C2294E1FECABAE007D065B /* log_test.cc */,
 				AB380D03201BC6E400D97691 /* ordered_code_test.cc */,
 				54740A531FC913E500713A1A /* secure_random_test.cc */,
+				54A0352B20A3B3D7003E0143 /* status_test_util.h */,
+				54A0352C20A3B3D7003E0143 /* status_test.cc */,
+				54A0352D20A3B3D7003E0143 /* statusor_test.cc */,
 				5436F32320008FAD006E51E3 /* string_printf_test.cc */,
 				AB380CFC201A2EE200D97691 /* string_util_test.cc */,
 			);
@@ -1489,6 +1505,7 @@
 				ABC1D7DD2023A04F00BA84F0 /* empty_credentials_provider_test.cc in Sources */,
 				DE2EF0861F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m in Sources */,
 				B686F2AF2023DDEE0028D6BE /* field_path_test.cc in Sources */,
+				54A0352A20A3B3BD003E0143 /* testutil.cc in Sources */,
 				5492E03120213FFC00B64F25 /* FSTLevelDBSpecTests.mm in Sources */,
 				B6FB468F208F9BAE00554BA2 /* executor_std_test.cc in Sources */,
 				5492E0B12021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm in Sources */,
@@ -1502,6 +1519,7 @@
 				5492E0A12021552D00B64F25 /* FSTMemoryLocalStoreTests.mm in Sources */,
 				5436F32420008FAD006E51E3 /* string_printf_test.cc in Sources */,
 				5492E067202154B900B64F25 /* FSTEventManagerTests.mm in Sources */,
+				54A0353020A3B3D8003E0143 /* statusor_test.cc in Sources */,
 				5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */,
 				54A0352620A3AED0003E0143 /* field_transform_test.mm in Sources */,
 				5492E055202154AB00B64F25 /* FIRDocumentSnapshotTests.mm in Sources */,
@@ -1513,6 +1531,7 @@
 				5492E056202154AB00B64F25 /* FIRFieldPathTests.mm in Sources */,
 				5492E03220213FFC00B64F25 /* FSTMockDatastore.mm in Sources */,
 				ABC1D7E12023A40C00BA84F0 /* token_test.cc in Sources */,
+				54A0353520A3D8CB003E0143 /* iterator_adaptors_test.cc in Sources */,
 				AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */,
 				AB7BAB342012B519001E0872 /* geo_point_test.cc in Sources */,
 				5492E0AD2021552D00B64F25 /* FSTMemoryMutationQueueTests.mm in Sources */,
@@ -1536,6 +1555,7 @@
 				54995F6F205B6E12004EFFA0 /* leveldb_key_test.cc in Sources */,
 				5492E065202154B900B64F25 /* FSTViewTests.mm in Sources */,
 				B6FB467D208E9D3C00554BA2 /* async_queue_test.cc in Sources */,
+				54A0352F20A3B3D8003E0143 /* status_test.cc in Sources */,
 				5492E03C2021401F00B64F25 /* XCTestCase+Await.mm in Sources */,
 				B6152AD7202A53CB000E5744 /* document_key_test.cc in Sources */,
 				5467FB08203E6A44009C9584 /* app_testing.mm in Sources */,
@@ -1892,8 +1912,9 @@
 					"$(inherited)",
 					"\"${PODS_ROOT}/../../..\"",
 					"\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
-					"\"${PODS_ROOT}/leveldb-library/include\"",
+					"\"${PODS_ROOT}/GoogleTest/googlemock/include\"",
 					"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
+					"\"${PODS_ROOT}/leveldb-library/include\"",
 				);
 				INFOPLIST_FILE = "Tests/Tests-Info.plist";
 				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
@@ -1925,8 +1946,9 @@
 					"$(inherited)",
 					"\"${PODS_ROOT}/../../..\"",
 					"\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
-					"\"${PODS_ROOT}/leveldb-library/include\"",
+					"\"${PODS_ROOT}/GoogleTest/googlemock/include\"",
 					"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
+					"\"${PODS_ROOT}/leveldb-library/include\"",
 				);
 				INFOPLIST_FILE = "Tests/Tests-Info.plist";
 				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";

+ 15 - 2
Firestore/Example/Tests/GoogleTest/GoogleTest.podspec

@@ -41,6 +41,8 @@ Google's C++ test framework.
   # (e.g. gtest.h). We don't need them because they're effectively empty:
   # they're compile-time hooks for third-party customization that we don't use.
   s.public_header_files = [
+    'googlemock/include/gmock/*.h',
+    'googlemock/include/gmock/internal/*.h',
     'googletest/include/gtest/*.h',
     'googletest/include/gtest/internal/*.h'
   ]
@@ -54,6 +56,9 @@ Google's C++ test framework.
   ]
 
   s.source_files = [
+    'googlemock/src/*.cc',
+    'googlemock/include/gmock/*.h',
+    'googlemock/include/gmock/internal/*.h',
     'googletest/src/*.cc',
     'googletest/include/gtest/*.h',
     'googletest/include/gtest/internal/*.h'
@@ -61,8 +66,11 @@ Google's C++ test framework.
 
   s.exclude_files = [
     # A convenience wrapper for a simple command-line build. If included in
-    # this build, results in duplicate symbols
+    # this build, results in duplicate symbols.
+    'googlemock/src/gmock-all.cc',
     'googletest/src/gtest-all.cc',
+    # Both gmock and gtest define a main function but we only need one.
+    'googletest/src/gtest_main.cc',
   ]
 
   s.library = 'c++'
@@ -70,12 +78,17 @@ Google's C++ test framework.
   # When building this pod there are headers in googletest/src.
   s.pod_target_xcconfig = {
     'HEADER_SEARCH_PATHS' =>
-      '"${PODS_ROOT}/GoogleTest/googletest/include" "${PODS_ROOT}/GoogleTest/googletest"'
+      '"${PODS_ROOT}/GoogleTest/googlemock/include" ' +
+      '"${PODS_ROOT}/GoogleTest/googletest/include" ' +
+      '"${PODS_ROOT}/GoogleTest/googletest"'
   }
 
   s.prepare_command = <<-'CMD'
     # Remove includes of files in internal/custom
     sed -i.bak -e '/include.*internal\/custom/ d' \
+      googlemock/include/gmock/gmock-matchers.h \
+      googlemock/include/gmock/gmock-generated-actions.h \
+      googlemock/include/gmock/internal/gmock-port.h \
       googletest/include/gtest/gtest-printers.h \
       googletest/include/gtest/internal/gtest-port.h \
       googletest/src/gtest-death-test.cc \

+ 106 - 0
scripts/check_test_inclusion.py

@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+
+# Copyright 2018 Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Verifies that all tests are a part of the project file.
+"""
+
+from __future__ import print_function
+import os
+import os.path
+import re
+import sys
+
+
+# Tests that are known not to compile in Xcode and can't be added there.
+EXCLUDED = frozenset([
+    # b/79496027
+    "Firestore/core/test/firebase/firestore/remote/serializer_test.cc",
+])
+
+
+def Main():
+  """Runs the style check."""
+
+  tests = FindTestFiles("Firestore/Example/Tests", "Firestore/core/test")
+  problems = CheckProject(
+      "Firestore/Example/Firestore.xcodeproj/project.pbxproj", tests)
+
+  if problems:
+    Error("Test files exist that are unreferenced in Xcode project files:")
+    for problem in problems:
+      Error(problem)
+    sys.exit(1)
+
+  sys.exit(0)
+
+
+def FindTestFiles(*test_dirs):
+  """Searches the given source roots for test files.
+
+  Args:
+    *test_dirs: A list of directories containing test sources.
+
+  Returns:
+    A list of test source filenames.
+  """
+
+  test_file_pattern = re.compile(r"(?:Tests?\.mm?|_test\.(?:cc|mm))$")
+
+  result = []
+  for test_dir in test_dirs:
+    for root, dirs, files in os.walk(test_dir):
+      del dirs  # unused
+      for basename in files:
+        filename = os.path.join(root, basename)
+        if filename not in EXCLUDED and test_file_pattern.search(basename):
+          result.append(filename)
+  return result
+
+
+def CheckProject(project_file, test_files):
+  """Checks the given project file for tests in the given test_dirs.
+
+  Args:
+    project_file: The path to an Xcode pbxproj file.
+    test_files: A list of all tests source files in the project.
+
+  Returns:
+    A sorted list of filenames that aren't referenced in the project_file.
+  """
+
+  # An dict of basename to filename
+  basenames = {os.path.basename(f) : f for f in test_files}
+
+  file_list_pattern = re.compile(r"/\* (\S+) in Sources \*/")
+  with open(project_file, "r") as fd:
+    for line in fd:
+      line = line.rstrip()
+      m = file_list_pattern.search(line)
+      if m:
+        basename = m.group(1)
+        if basename in basenames:
+          del basenames[basename]
+
+  return sorted(basenames.values())
+
+
+def Error(message, *args):
+  message %= args
+  print(message, file=sys.stderr)
+
+
+if __name__ == "__main__":
+  Main()