Skip to content

Add build infrastructure for Codable support in Firestore #815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3598b86
Add Firestore_SwiftTests_iOS target to Xcode
wilhuff Feb 20, 2018
959cc57
Clean up generated Firestore_SwiftTests_iOS test target
wilhuff Feb 20, 2018
ad832a1
Add FirebaseFirestoreSwift podspec
wilhuff Feb 20, 2018
24daa10
Add Firestore_SwiftTests_iOS to the Podfile
wilhuff Feb 20, 2018
6fc2dd4
Add CodableGeoPoint
wilhuff Feb 20, 2018
b5d72b0
Move Firestore_SwiftTests_iOS to the top-level of the Podfile
wilhuff Feb 20, 2018
c719b85
Add CodableGeoPointTests to the project
wilhuff Feb 20, 2018
74f6954
Merge branch 'master' into wilhuff/codable
wilhuff Feb 23, 2018
cc804c7
Restore Firestore.xcodeproj from master
wilhuff Feb 23, 2018
d468408
Add Firestore_SwiftTests_iOS target
wilhuff Feb 23, 2018
2a1c056
Reorder Firestore_SwiftTests_iOS
wilhuff Feb 23, 2018
056d39a
Rename Firestore_SwiftTests_iOS folder to SwiftTests
wilhuff Feb 23, 2018
20861c8
Remove Firestore_SwiftTests_iOS.swift which does not exist
wilhuff Feb 24, 2018
d00667f
Integrate CocoaPods
wilhuff Feb 24, 2018
1f7b20f
Add Firestore_SwiftTests_iOS to Firestore_Tests
wilhuff Feb 24, 2018
772184a
Add Firestore_SwiftTests_iOS to AllTests
wilhuff Feb 24, 2018
0898c4e
Reorder targets
wilhuff Feb 24, 2018
11f8964
Add Codable tests to Firestore_SwiftTests_iOS
wilhuff Feb 24, 2018
32bae6b
Enable Firestore_SwiftTests_iOS
wilhuff Feb 24, 2018
cafbb79
Adjust Info.plist location
wilhuff Feb 24, 2018
dafdf76
Remove default test files
wilhuff Feb 24, 2018
c6020cd
Reformat Firestore/Swift
wilhuff Feb 24, 2018
f40acce
Version FirebaseFirestoreSwift separately
wilhuff Feb 24, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions FirebaseFirestoreSwift.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# Be sure to run `pod lib lint FirebaseFirestoreSwift.podspec' to ensure this is a
# valid spec before submitting.
#

Pod::Spec.new do |s|
s.name = 'FirebaseFirestoreSwift'
s.version = '0.10.1'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to explicitly version this separately since it presumably doesn't need to stay in lock step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

s.summary = 'Google Cloud Firestore for iOS Swift Extensions'

s.description = <<-DESC
Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development.
DESC

s.homepage = 'https://developers.google.com/'
s.license = { :type => 'Apache', :file => 'LICENSE' }
s.authors = 'Google, Inc.'

s.source = {
:git => 'https://github.com/Firebase/firebase-ios-sdk.git',
:tag => s.version.to_s
}

s.swift_version = '4.0'
s.ios.deployment_target = '8.0'

s.cocoapods_version = '>= 1.4.0'
s.static_framework = true
s.prefix_header_file = false

s.requires_arc = true
s.source_files = [
'Firestore/Swift/Source/**/*.swift',
]

s.dependency 'FirebaseFirestore', "= #{s.version}"
end
266 changes: 264 additions & 2 deletions Firestore/Example/Firestore.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "54C9EDF02040E16300A969CD"
BuildableName = "Firestore_SwiftTests_iOS.xctest"
BlueprintName = "Firestore_SwiftTests_iOS"
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand Down Expand Up @@ -49,6 +63,16 @@
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "54C9EDF02040E16300A969CD"
BuildableName = "Firestore_SwiftTests_iOS.xctest"
BlueprintName = "Firestore_SwiftTests_iOS"
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "54C9EDF02040E16300A969CD"
BuildableName = "Firestore_SwiftTests_iOS.xctest"
BlueprintName = "Firestore_SwiftTests_iOS"
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand All @@ -39,7 +53,26 @@
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "54C9EDF02040E16300A969CD"
BuildableName = "Firestore_SwiftTests_iOS.xctest"
BlueprintName = "Firestore_SwiftTests_iOS"
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6003F5AD195388D20070C39A"
BuildableName = "Firestore_Tests.xctest"
BlueprintName = "Firestore_Tests"
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
Expand Down Expand Up @@ -72,6 +105,15 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6003F5AD195388D20070C39A"
BuildableName = "Firestore_Tests.xctest"
BlueprintName = "Firestore_Tests"
ReferencedContainer = "container:Firestore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
Expand Down
5 changes: 5 additions & 0 deletions Firestore/Example/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ target 'Firestore_Example' do

pod 'OCMock'
end

target 'Firestore_SwiftTests_iOS' do
pod 'FirebaseFirestore', :path => '../../'
pod 'FirebaseFirestoreSwift', :path => '../../'
end
end

target 'SwiftBuildTest' do
Expand Down
62 changes: 62 additions & 0 deletions Firestore/Swift/Source/Codable/CodableGeoPoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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.
*/

import FirebaseFirestore

/**
* A protocol describing the encodable properties of a GeoPoint.
*
* Note: this protocol exists as a workaround for the Swift compiler: if the GeoPoint class was
* extended directly to conform to Codable, the methods implementing the protcol would be need to be
* marked required but that can't be done in an extension. Declaring the extension on the protocol
* sidesteps this issue.
*/
fileprivate protocol CodableGeoPoint: Codable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we move to Source builds, hopefully this won't be required!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's going to matter. This exists because of limitations in the Swift compiler. So long as GeoPoint is implemented in Objective-C and can't implement Codable directly these will be required.

var latitude: Double { get }
var longitude: Double { get }

init(latitude: Double, longitude: Double)
}

/** The keys in a GeoPoint. Must match the properties of CodableGeoPoint. */
fileprivate enum GeoPointKeys: String, CodingKey {
case latitude
case longitude
}

/**
* An extension of GeoPoint that implements the behavior of the Codable protocol.
*
* Note: this is implemented manually here because the Swift compiler can't synthesize these methods
* when declaring an extension to conform to Codable.
*/
extension CodableGeoPoint {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: GeoPointKeys.self)
let latitude = try container.decode(Double.self, forKey: .latitude)
let longitude = try container.decode(Double.self, forKey: .longitude)
self.init(latitude: latitude, longitude: longitude)
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: GeoPointKeys.self)
try container.encode(latitude, forKey: .latitude)
try container.encode(longitude, forKey: .longitude)
}
}

/** Extends GeoPoint to conform to Codable. */
extension GeoPoint: CodableGeoPoint {}
49 changes: 49 additions & 0 deletions Firestore/Swift/Tests/Codable/CodableGeoPointTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.
*/

import FirebaseFirestore
import FirebaseFirestoreSwift
import Foundation
import XCTest

class CodableGeoPointTests: XCTestCase {
func testGeoPointEncodes() {
let geoPoint = GeoPoint(latitude: 37.77493, longitude: -122.41942)

let jsonData = try! JSONEncoder().encode(geoPoint)
let json = String(data:jsonData, encoding:.utf8)!

// The ordering of attributes in the JSON output is not guaranteed, nor is the rounding of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"nor is the rounding of the values"

Is this going to be an issue do you think? Or is it just .0001 off like below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue here is that we don't control the JSON encoding/decoding and this test doesn't really care about any kind of conformance in that scenario. If users use this serialization and don't like the results they can take it up with the authors of JSONEncoder.

I'm validating that GeoPoint conforms to Codable without any dependency on Firestore or snapshots.

// the values so just verify that each required property is present and that the value
// starts as expected.
XCTAssert(json.contains("\"latitude\":37."))
XCTAssert(json.contains("\"longitude\":-122."))
}

func testGeoPointDecodes() {
let json = """
{
"latitude": 37.77493,
"longitude": -122.41942
}
""";
let jsonData: Data = json.data(using:.utf8)!

let geoPoint = try! JSONDecoder().decode(GeoPoint.self, from: jsonData)
XCTAssertEqual(37.77493, geoPoint.latitude, accuracy: 0.0001)
XCTAssertEqual(-122.41942, geoPoint.longitude, accuracy: 0.0001)
}
}
22 changes: 22 additions & 0 deletions Firestore/Swift/Tests/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>