From 602c262c6b3af01ac8426c8e18bc96f7e2b36bac Mon Sep 17 00:00:00 2001 From: Gil Date: Thu, 10 May 2018 10:22:38 -0700 Subject: 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 --- .travis.yml | 1 + .../Example/Firestore.xcodeproj/project.pbxproj | 26 ++++- .../Example/Tests/GoogleTest/GoogleTest.podspec | 17 +++- scripts/check_test_inclusion.py | 106 +++++++++++++++++++++ 4 files changed, 146 insertions(+), 4 deletions(-) create mode 100755 scripts/check_test_inclusion.py diff --git a/.travis.yml b/.travis.yml index 7e138b2..4376600 100644 --- a/.travis.yml +++ b/.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 diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 131771b..ce56b8b 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/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 = ""; }; 54A0352220A3AEC3003E0143 /* transform_operations_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = transform_operations_test.mm; sourceTree = ""; }; 54A0352320A3AEC3003E0143 /* field_transform_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = field_transform_test.mm; sourceTree = ""; }; + 54A0352820A3B3BD003E0143 /* testutil.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testutil.cc; sourceTree = ""; }; + 54A0352920A3B3BD003E0143 /* testutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testutil.h; sourceTree = ""; }; + 54A0352B20A3B3D7003E0143 /* status_test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status_test_util.h; sourceTree = ""; }; + 54A0352C20A3B3D7003E0143 /* status_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status_test.cc; sourceTree = ""; }; + 54A0352D20A3B3D7003E0143 /* statusor_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statusor_test.cc; sourceTree = ""; }; + 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iterator_adaptors_test.cc; sourceTree = ""; }; 54C2294E1FECABAE007D065B /* log_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log_test.cc; sourceTree = ""; }; 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 = ""; }; @@ -519,6 +529,8 @@ children = ( 5467FB06203E6A44009C9584 /* app_testing.h */, 5467FB07203E6A44009C9584 /* app_testing.mm */, + 54A0352820A3B3BD003E0143 /* testutil.cc */, + 54A0352920A3B3BD003E0143 /* testutil.h */, ); path = testutil; sourceTree = ""; @@ -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}"; diff --git a/Firestore/Example/Tests/GoogleTest/GoogleTest.podspec b/Firestore/Example/Tests/GoogleTest/GoogleTest.podspec index 064fc59..0ecba3d 100644 --- a/Firestore/Example/Tests/GoogleTest/GoogleTest.podspec +++ b/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 \ diff --git a/scripts/check_test_inclusion.py b/scripts/check_test_inclusion.py new file mode 100755 index 0000000..7f5f354 --- /dev/null +++ b/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() -- cgit v1.2.3