Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0c184edc4 | |||
| a55a22fc13 | |||
| 39c062c911 | |||
| 054363df0c | |||
| e4497d59dd | |||
| fdfb259f3f | |||
| c48c648c81 | |||
| 2849da37a6 | |||
| daab317c37 | |||
| 091edd90a2 |
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: About
|
||||||
|
permalink: /about/
|
||||||
|
---
|
||||||
|
|
||||||
|
This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](http://jekyllrb.com/)
|
||||||
|
|
||||||
|
You can find the source code for the Jekyll new theme at:
|
||||||
|
{% include icon-github.html username="jglovier" %} /
|
||||||
|
[jekyll-new](https://github.com/jglovier/jekyll-new)
|
||||||
|
|
||||||
|
You can find the source code for Jekyll at
|
||||||
|
{% include icon-github.html username="jekyll" %} /
|
||||||
|
[jekyll](https://github.com/jekyll/jekyll)
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
try:
|
|
||||||
project: 'CoreStore.xcworkspace'
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: [JohnEstropia]
|
|
||||||
@@ -1,16 +1,3 @@
|
|||||||
CoreStoreDemo/CoreStoreDemo.xcodeproj/project.xcworkspace/xcuserdata
|
_site
|
||||||
CoreStore.xcodeproj/project.xcworkspace/xcuserdata
|
.sass-cache
|
||||||
CoreStore.xcodeproj/xcuserdata
|
.jekyll-metadata
|
||||||
CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata
|
|
||||||
Carthage/Build
|
|
||||||
CoreStore.xcworkspace/xcuserdata
|
|
||||||
.DS_Store
|
|
||||||
DerivedData
|
|
||||||
*.orig
|
|
||||||
build
|
|
||||||
Playground_macOS.playground/playground.xcworkspace/xcuserdata
|
|
||||||
.swiftpm/xcode/package.xcworkspace/xcuserdata
|
|
||||||
.swiftpm/xcode/xcuserdata
|
|
||||||
Playground_iOS.playground/playground.xcworkspace/xcuserdata
|
|
||||||
LegacyDemo/LegacyDemo.xcodeproj/xcuserdata
|
|
||||||
Demo/Demo.xcodeproj/xcuserdata
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
author: John Estropia
|
|
||||||
author_url: https://github.com/JohnEstropia
|
|
||||||
github_url: https://github.com/JohnEstropia/CoreStore
|
|
||||||
module: CoreStore
|
|
||||||
readme: README.md
|
|
||||||
include: Sources/*
|
|
||||||
output: docs
|
|
||||||
theme: fullwidth
|
|
||||||
clean: true
|
|
||||||
skip_undocumented: true
|
|
||||||
xcodebuild_arguments:
|
|
||||||
- -sdk
|
|
||||||
- iphonesimulator
|
|
||||||
- -scheme
|
|
||||||
- CoreStore iOS
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?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>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?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>SchemeUserState</key>
|
|
||||||
<dict>
|
|
||||||
<key>CoreStore.xcscheme_^#shared#^_</key>
|
|
||||||
<dict>
|
|
||||||
<key>orderHint</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
|
Before Width: | Height: | Size: 53 KiB |
@@ -1,22 +0,0 @@
|
|||||||
Pod::Spec.new do |s|
|
|
||||||
s.name = "CoreStore"
|
|
||||||
s.version = "7.3.0"
|
|
||||||
s.swift_version = "5.3"
|
|
||||||
s.license = "MIT"
|
|
||||||
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
|
||||||
s.documentation_url = "https://JohnEstropia.github.io/CoreStore"
|
|
||||||
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
|
|
||||||
s.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" }
|
|
||||||
s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s }
|
|
||||||
|
|
||||||
s.ios.deployment_target = "10.0"
|
|
||||||
s.osx.deployment_target = "10.12"
|
|
||||||
s.watchos.deployment_target = "3.0"
|
|
||||||
s.tvos.deployment_target = "10.0"
|
|
||||||
|
|
||||||
s.source_files = "Sources", "Sources/**/*.{swift,h,m}"
|
|
||||||
s.public_header_files = "Sources/**/*.h"
|
|
||||||
s.frameworks = "Foundation", "CoreData"
|
|
||||||
s.requires_arc = true
|
|
||||||
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D DEBUG', 'OTHER_LDFLAGS' => '-weak_framework Combine -weak_framework SwiftUI' }
|
|
||||||
end
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:CoreStore.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<?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>IDESourceControlProjectFavoriteDictionaryKey</key>
|
|
||||||
<false/>
|
|
||||||
<key>IDESourceControlProjectIdentifier</key>
|
|
||||||
<string>F347F55F-7F5C-4476-9148-6E902F06E4AD</string>
|
|
||||||
<key>IDESourceControlProjectName</key>
|
|
||||||
<string>CoreStore</string>
|
|
||||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
|
||||||
<dict>
|
|
||||||
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
|
|
||||||
<string>github.com:JohnEstropia/CoreStore.git</string>
|
|
||||||
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
|
|
||||||
<string>github.com:JohnEstropia/GCDKit.git</string>
|
|
||||||
</dict>
|
|
||||||
<key>IDESourceControlProjectPath</key>
|
|
||||||
<string>CoreStore.xcodeproj</string>
|
|
||||||
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
|
||||||
<dict>
|
|
||||||
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
|
|
||||||
<string>../..</string>
|
|
||||||
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
|
|
||||||
<string>../..Libraries/GCDKit</string>
|
|
||||||
</dict>
|
|
||||||
<key>IDESourceControlProjectURL</key>
|
|
||||||
<string>github.com:JohnEstropia/CoreStore.git</string>
|
|
||||||
<key>IDESourceControlProjectVersion</key>
|
|
||||||
<integer>111</integer>
|
|
||||||
<key>IDESourceControlProjectWCCIdentifier</key>
|
|
||||||
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
|
|
||||||
<key>IDESourceControlProjectWCConfigurations</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
|
||||||
<string>public.vcs.git</string>
|
|
||||||
<key>IDESourceControlWCCIdentifierKey</key>
|
|
||||||
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
|
|
||||||
<key>IDESourceControlWCCName</key>
|
|
||||||
<string>CoreStore</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
|
||||||
<string>public.vcs.git</string>
|
|
||||||
<key>IDESourceControlWCCIdentifierKey</key>
|
|
||||||
<string>8B2E522D57154DFA93A06982C36315ECBEA4FA97</string>
|
|
||||||
<key>IDESourceControlWCCName</key>
|
|
||||||
<string>GCDKit</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
|
|
||||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
|
|
||||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
|
|
||||||
},
|
|
||||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F347F55F-7F5C-4476-9148-6E902F06E4AD",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
|
||||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
|
|
||||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
|
|
||||||
},
|
|
||||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
|
||||||
{
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/CoreStore.git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/GCDKit.git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<?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>IDESourceControlProjectFavoriteDictionaryKey</key>
|
|
||||||
<false/>
|
|
||||||
<key>IDESourceControlProjectIdentifier</key>
|
|
||||||
<string>FE56D6CC-DFA6-4581-B49D-F2486374A545</string>
|
|
||||||
<key>IDESourceControlProjectName</key>
|
|
||||||
<string>project</string>
|
|
||||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
|
||||||
<dict>
|
|
||||||
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
|
|
||||||
<string>github.com:JohnEstropia/HardcoreData.git</string>
|
|
||||||
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
|
|
||||||
<string>github.com:JohnEstropia/GCDKit.git</string>
|
|
||||||
</dict>
|
|
||||||
<key>IDESourceControlProjectPath</key>
|
|
||||||
<string>HardcoreData.xcodeproj/project.xcworkspace</string>
|
|
||||||
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
|
||||||
<dict>
|
|
||||||
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
|
|
||||||
<string>../..</string>
|
|
||||||
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
|
|
||||||
<string>../..Libraries/GCDKit</string>
|
|
||||||
</dict>
|
|
||||||
<key>IDESourceControlProjectURL</key>
|
|
||||||
<string>github.com:JohnEstropia/HardcoreData.git</string>
|
|
||||||
<key>IDESourceControlProjectVersion</key>
|
|
||||||
<integer>111</integer>
|
|
||||||
<key>IDESourceControlProjectWCCIdentifier</key>
|
|
||||||
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
|
|
||||||
<key>IDESourceControlProjectWCConfigurations</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
|
||||||
<string>public.vcs.git</string>
|
|
||||||
<key>IDESourceControlWCCIdentifierKey</key>
|
|
||||||
<string>8B2E522D57154DFA93A06982C36315ECBEA4FA97</string>
|
|
||||||
<key>IDESourceControlWCCName</key>
|
|
||||||
<string>GCDKit</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
|
||||||
<string>public.vcs.git</string>
|
|
||||||
<key>IDESourceControlWCCIdentifierKey</key>
|
|
||||||
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
|
|
||||||
<key>IDESourceControlWCCName</key>
|
|
||||||
<string>HardcoreData</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?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>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1020"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore OSX"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore OSX"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<Testables>
|
|
||||||
<TestableReference
|
|
||||||
skipped = "NO">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B52DD17C1BE1F8CC00949AFE"
|
|
||||||
BuildableName = "CoreStoreTests.xctest"
|
|
||||||
BlueprintName = "CoreStoreTests OSX"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</TestableReference>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore OSX"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore OSX"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1020"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore iOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "NO"
|
|
||||||
buildForProfiling = "NO"
|
|
||||||
buildForArchiving = "NO"
|
|
||||||
buildForAnalyzing = "NO">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
|
||||||
BuildableName = "CoreStoreTests.xctest"
|
|
||||||
BlueprintName = "CoreStoreTests iOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore iOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<AdditionalOptions>
|
|
||||||
<AdditionalOption
|
|
||||||
key = "NSZombieEnabled"
|
|
||||||
value = "YES"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</AdditionalOption>
|
|
||||||
</AdditionalOptions>
|
|
||||||
<Testables>
|
|
||||||
<TestableReference
|
|
||||||
skipped = "NO">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
|
||||||
BuildableName = "CoreStoreTests.xctest"
|
|
||||||
BlueprintName = "CoreStoreTests iOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</TestableReference>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore iOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<CommandLineArguments>
|
|
||||||
<CommandLineArgument
|
|
||||||
argument = "-com.apple.CoreData.SQLDebug 2"
|
|
||||||
isEnabled = "NO">
|
|
||||||
</CommandLineArgument>
|
|
||||||
</CommandLineArguments>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore iOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Release">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1020"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore tvOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore tvOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<Testables>
|
|
||||||
<TestableReference
|
|
||||||
skipped = "NO">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "82BA18911C4BBCBA00A0916E"
|
|
||||||
BuildableName = "CoreStoreTests.xctest"
|
|
||||||
BlueprintName = "CoreStoreTests tvOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</TestableReference>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore tvOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore tvOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1020"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B563216E1BD65082006C9394"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore watchOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<Testables>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B563216E1BD65082006C9394"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore watchOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B563216E1BD65082006C9394"
|
|
||||||
BuildableName = "CoreStore.framework"
|
|
||||||
BlueprintName = "CoreStore watchOS"
|
|
||||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "group:Demo/Demo.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:CoreStore.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:/Users/JohnEstropia/Documents/XCodeProjects/CoreStore/LegacyDemo/LegacyDemo.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
|
|
||||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
|
|
||||||
"95438028B10BBB846574013D29F154A00556A9D1" : 0,
|
|
||||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
|
|
||||||
},
|
|
||||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "EBFDEFFE-8BA0-441A-862A-1DE28AA5CD21",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
|
||||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStore\/Carthage\/Checkouts\/GCDKit\/",
|
|
||||||
"95438028B10BBB846574013D29F154A00556A9D1" : "CoreStore\/Carthage\/Checkouts\/Nimble\/",
|
|
||||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
|
|
||||||
},
|
|
||||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcworkspace",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
|
||||||
{
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/CoreStore",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/GCDKit.git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Quick\/Nimble.git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
|
||||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "95438028B10BBB846574013D29F154A00556A9D1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?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>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?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/>
|
|
||||||
</plist>
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
//
|
|
||||||
// BaseTestCase.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - BaseTestCase
|
|
||||||
|
|
||||||
class BaseTestCase: XCTestCase {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) throws -> Void) {
|
|
||||||
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
try configurations.forEach {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(
|
|
||||||
SQLiteStore(
|
|
||||||
fileURL: SQLiteStore.defaultRootDirectory
|
|
||||||
.appendingPathComponent(UUID().uuidString)
|
|
||||||
.appendingPathComponent("\(Self.self)_\(($0 ?? "-null-")).sqlite"),
|
|
||||||
configuration: $0,
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
try closure(stack)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.coreStoreDumpString)
|
|
||||||
}
|
|
||||||
self.addTeardownBlock {
|
|
||||||
stack.unsafeRemoveAllPersistentStoresAndWait()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
|
|
||||||
|
|
||||||
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations(expectations))
|
|
||||||
defer {
|
|
||||||
|
|
||||||
self.checkExpectationsImmediately()
|
|
||||||
CoreStoreDefaults.logger = TestLogger([:])
|
|
||||||
}
|
|
||||||
return try closure()
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func expectLogger(_ expectations: [TestLogger.Expectation: XCTestExpectation]) {
|
|
||||||
|
|
||||||
CoreStoreDefaults.logger = TestLogger(expectations)
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func expectError<T>(code: CoreStoreErrorCode, closure: () throws -> T) {
|
|
||||||
|
|
||||||
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations([.logError]))
|
|
||||||
defer {
|
|
||||||
|
|
||||||
self.checkExpectationsImmediately()
|
|
||||||
CoreStoreDefaults.logger = TestLogger([:])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
_ = try closure()
|
|
||||||
}
|
|
||||||
catch let error as CoreStoreError {
|
|
||||||
|
|
||||||
if error.errorCode == code.rawValue {
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
XCTFail("Expected error code \(code) different from actual error: \((error as NSError).coreStoreDumpString)")
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
XCTFail("Error not wrapped as \(Internals.typeName(CoreStoreError.self)): \((error as NSError).coreStoreDumpString)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
|
|
||||||
|
|
||||||
var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:]
|
|
||||||
for expectation in expectations {
|
|
||||||
|
|
||||||
testExpectations[expectation] = self.expectation(description: "Logger Expectation: \(expectation)")
|
|
||||||
}
|
|
||||||
return testExpectations
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func checkExpectationsImmediately() {
|
|
||||||
|
|
||||||
self.waitForExpectations(timeout: 0, handler: { _ in })
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func waitAndCheckExpectations() {
|
|
||||||
|
|
||||||
self.waitForExpectations(timeout: 10, handler: {_ in })
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: XCTestCase
|
|
||||||
|
|
||||||
override func setUp() {
|
|
||||||
|
|
||||||
super.setUp()
|
|
||||||
self.deleteStores()
|
|
||||||
CoreStoreDefaults.logger = TestLogger([:])
|
|
||||||
}
|
|
||||||
|
|
||||||
override func tearDown() {
|
|
||||||
|
|
||||||
CoreStoreDefaults.logger = DefaultLogger()
|
|
||||||
self.deleteStores()
|
|
||||||
super.tearDown()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private func deleteStores() {
|
|
||||||
|
|
||||||
_ = try? FileManager.default.removeItem(at: SQLiteStore.defaultRootDirectory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - TestLogger
|
|
||||||
|
|
||||||
class TestLogger: CoreStoreLogger {
|
|
||||||
|
|
||||||
enum Expectation {
|
|
||||||
|
|
||||||
case logWarning
|
|
||||||
case logFatal
|
|
||||||
case logError
|
|
||||||
case assertionFailure
|
|
||||||
case fatalError
|
|
||||||
}
|
|
||||||
|
|
||||||
init(_ expectations: [Expectation: XCTestExpectation]) {
|
|
||||||
|
|
||||||
self.expectations = expectations
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: CoreStoreLogger
|
|
||||||
|
|
||||||
var enableObjectConcurrencyDebugging: Bool = true
|
|
||||||
|
|
||||||
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
|
||||||
|
|
||||||
switch level {
|
|
||||||
|
|
||||||
case .warning: self.fulfill(.logWarning)
|
|
||||||
case .fatal: self.fulfill(.logFatal)
|
|
||||||
default: break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
|
||||||
|
|
||||||
self.fulfill(.logError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
|
||||||
|
|
||||||
if condition() {
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.fulfill(.assertionFailure)
|
|
||||||
}
|
|
||||||
|
|
||||||
func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
|
||||||
|
|
||||||
self.fulfill(.fatalError)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private var expectations: [Expectation: XCTestExpectation]
|
|
||||||
|
|
||||||
private func fulfill(_ expectation: Expectation) {
|
|
||||||
|
|
||||||
if let instance = self.expectations[expectation] {
|
|
||||||
|
|
||||||
instance.fulfill()
|
|
||||||
self.expectations[expectation] = nil
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail("Unexpected Logger Action: \(expectation)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
//
|
|
||||||
// BaseTestDataTestCase.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - BaseTestDataTestCase
|
|
||||||
|
|
||||||
class BaseTestDataTestCase: BaseTestCase {
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
let dateFormatter: DateFormatter = Internals.with {
|
|
||||||
|
|
||||||
let formatter = DateFormatter()
|
|
||||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
||||||
formatter.timeZone = TimeZone(identifier: "UTC")
|
|
||||||
formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
|
|
||||||
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
|
|
||||||
return formatter
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func prepareTestDataForStack(_ stack: DataStack, configurations: [ModelConfiguration] = [nil]) {
|
|
||||||
|
|
||||||
try! stack.perform(
|
|
||||||
synchronous: { (transaction) in
|
|
||||||
|
|
||||||
for (configurationIndex, configuration) in configurations.enumerated() {
|
|
||||||
|
|
||||||
let configurationOrdinal = configurationIndex + 1
|
|
||||||
if configuration == nil || configuration == "Config1" {
|
|
||||||
|
|
||||||
for idIndex in 1 ... 5 {
|
|
||||||
|
|
||||||
let object = transaction.create(Into<TestEntity1>(configuration))
|
|
||||||
object.testEntityID = NSNumber(value: (configurationOrdinal * 100) + idIndex)
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: idIndex)
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
|
||||||
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
|
||||||
|
|
||||||
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
|
|
||||||
object.testString = string
|
|
||||||
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if configuration == nil || configuration == "Config2" {
|
|
||||||
|
|
||||||
for idIndex in 1 ... 5 {
|
|
||||||
|
|
||||||
let object = transaction.create(Into<TestEntity2>(configuration))
|
|
||||||
object.testEntityID = NSNumber(value: (configurationOrdinal * 200) + idIndex)
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: idIndex)
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
|
||||||
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
|
||||||
|
|
||||||
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
|
|
||||||
object.testString = string
|
|
||||||
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
//
|
|
||||||
// BridgingTests.h
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <XCTest/XCTest.h>
|
|
||||||
|
|
||||||
@interface BridgingTests : XCTestCase
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
//
|
|
||||||
// BridgingTests.m
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "BridgingTests.h"
|
|
||||||
#import <CoreStore/CoreStore.h>
|
|
||||||
#import <CoreStore/CoreStore-Swift.h>
|
|
||||||
#import "CoreStoreTests-Swift.h"
|
|
||||||
|
|
||||||
@import CoreData;
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - BridgingTests
|
|
||||||
|
|
||||||
@implementation BridgingTests
|
|
||||||
|
|
||||||
- (void)test_ThatFlags_HaveCorrectValues {
|
|
||||||
|
|
||||||
XCTAssertEqual(CSLocalStorageOptionsNone, 0);
|
|
||||||
XCTAssertEqual(CSLocalStorageOptionsRecreateStoreOnModelMismatch, 1);
|
|
||||||
XCTAssertEqual(CSLocalStorageOptionsPreventProgressiveMigration, 2);
|
|
||||||
XCTAssertEqual(CSLocalStorageOptionsAllowSynchronousLightweightMigration, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatKeyPaths_AreCorrect {
|
|
||||||
|
|
||||||
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testNumber), @"testNumber");
|
|
||||||
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testString), @"testString");
|
|
||||||
XCTAssertEqualObjects(CSKeyPathOperator(count, TestEntity1, testString), @"@count.testString");
|
|
||||||
XCTAssertEqualObjects(CSKeyPathOperator(max, TestEntity1, testNumber), @"@max.testNumber");
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatFromClauses_BridgeCorrectly {
|
|
||||||
|
|
||||||
{
|
|
||||||
CSFrom *from = CSFromClass([TestEntity1 class]);
|
|
||||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
|
||||||
XCTAssertNil(from.configurations);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSFrom *from = CSFromClass([TestEntity1 class], [NSNull null]);
|
|
||||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
|
||||||
|
|
||||||
NSArray *configurations = @[[NSNull null]];
|
|
||||||
XCTAssertEqualObjects(from.configurations, configurations);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSFrom *from = CSFromClass([TestEntity1 class], @"Config1");
|
|
||||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
|
||||||
|
|
||||||
NSArray *configurations = @[@"Config1"];
|
|
||||||
XCTAssertEqualObjects(from.configurations, configurations);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSFrom *from = CSFromClass([TestEntity1 class], @[[NSNull null], @"Config2"]);
|
|
||||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
|
||||||
|
|
||||||
NSArray *configurations = @[[NSNull null], @"Config2"];
|
|
||||||
XCTAssertEqualObjects(from.configurations, configurations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatWhereClauses_BridgeCorrectly {
|
|
||||||
|
|
||||||
{
|
|
||||||
CSWhere *where = CSWhereFormat(@"%K == %@", @"key", @"value");
|
|
||||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
|
|
||||||
XCTAssertEqualObjects(where.predicate, predicate);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSWhere *where = CSWhereValue(YES);
|
|
||||||
NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
|
|
||||||
XCTAssertEqualObjects(where.predicate, predicate);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSWhere *where = CSWherePredicate([NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]);
|
|
||||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
|
|
||||||
XCTAssertEqualObjects(where.predicate, predicate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatOrderByClauses_BridgeCorrectly {
|
|
||||||
|
|
||||||
{
|
|
||||||
CSOrderBy *orderBy = CSOrderByKey(CSSortAscending(@"key"));
|
|
||||||
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:YES]]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSOrderBy *orderBy = CSOrderByKey(CSSortDescending(@"key"));
|
|
||||||
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:NO]]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSOrderBy *orderBy = CSOrderByKeys(CSSortAscending(@"key1"), CSSortDescending(@"key2"), nil);
|
|
||||||
NSArray *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"key1" ascending:YES],
|
|
||||||
[NSSortDescriptor sortDescriptorWithKey:@"key2" ascending:NO]];
|
|
||||||
XCTAssertEqualObjects(orderBy.sortDescriptors, sortDescriptors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatGroupByClauses_BridgeCorrectly {
|
|
||||||
|
|
||||||
{
|
|
||||||
CSGroupBy *groupBy = CSGroupByKeyPath(@"key");
|
|
||||||
XCTAssertEqualObjects(groupBy.keyPaths, @[@"key"]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSGroupBy *groupBy = CSGroupByKeyPaths(@[@"key1", @"key2"]);
|
|
||||||
|
|
||||||
NSArray *keyPaths = @[@"key1", @"key2"];
|
|
||||||
XCTAssertEqualObjects(groupBy.keyPaths, keyPaths);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatTweakClauses_BridgeCorrectly {
|
|
||||||
|
|
||||||
CSTweak *tweak = CSTweakRequest(^(NSFetchRequest * _Nonnull fetchRequest) {
|
|
||||||
|
|
||||||
fetchRequest.fetchLimit = 100;
|
|
||||||
});
|
|
||||||
NSFetchRequest *request = [NSFetchRequest new];
|
|
||||||
tweak.block(request);
|
|
||||||
XCTAssertEqual(request.fetchLimit, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatIntoClauses_BridgeCorrectly {
|
|
||||||
|
|
||||||
{
|
|
||||||
CSInto *into = CSIntoClass([TestEntity1 class]);
|
|
||||||
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSInto *into = CSIntoClass([TestEntity1 class], [NSNull null]);
|
|
||||||
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
|
|
||||||
XCTAssertNil(into.configuration);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CSInto *into = CSIntoClass([TestEntity1 class], @"Config1");
|
|
||||||
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
|
|
||||||
XCTAssertEqualObjects(into.configuration, @"Config1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatDataStacks_BridgeCorrectly {
|
|
||||||
|
|
||||||
CSDataStack *dataStack = [[CSDataStack alloc]
|
|
||||||
initWithXcodeModelName:@"Model"
|
|
||||||
bundle:[NSBundle bundleForClass:[self class]]
|
|
||||||
versionChain:nil];
|
|
||||||
XCTAssertNotNil(dataStack);
|
|
||||||
|
|
||||||
NSError *memoryError;
|
|
||||||
CSInMemoryStore *memoryStorage = [dataStack
|
|
||||||
addInMemoryStorageAndWait:[CSInMemoryStore new]
|
|
||||||
error:&memoryError];
|
|
||||||
XCTAssertNotNil(memoryStorage);
|
|
||||||
XCTAssertEqualObjects([[memoryStorage class] storeType], [CSInMemoryStore storeType]);
|
|
||||||
XCTAssertEqualObjects([[memoryStorage class] storeType], NSInMemoryStoreType);
|
|
||||||
XCTAssertNil(memoryStorage.configuration);
|
|
||||||
XCTAssertNil(memoryStorage.storeOptions);
|
|
||||||
XCTAssertNil(memoryError);
|
|
||||||
|
|
||||||
NSError *sqliteError;
|
|
||||||
CSSQLiteStore *sqliteStorage = [dataStack
|
|
||||||
addSQLiteStorageAndWait:[CSSQLiteStore new]
|
|
||||||
error:&sqliteError];
|
|
||||||
XCTAssertNotNil(sqliteStorage);
|
|
||||||
XCTAssertEqualObjects([[sqliteStorage class] storeType], [CSSQLiteStore storeType]);
|
|
||||||
XCTAssertEqualObjects([[sqliteStorage class] storeType], NSSQLiteStoreType);
|
|
||||||
XCTAssertNil(sqliteStorage.configuration);
|
|
||||||
NSDictionary *storeOptions;
|
|
||||||
if (@available(iOS 11.0, macOS 10.13, tvOS 11.0, *)) {
|
|
||||||
|
|
||||||
storeOptions = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" },
|
|
||||||
NSBinaryStoreInsecureDecodingCompatibilityOption: @YES };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
storeOptions = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" }};
|
|
||||||
}
|
|
||||||
XCTAssertEqualObjects(sqliteStorage.storeOptions, storeOptions);
|
|
||||||
XCTAssertNil(sqliteError);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)test_ThatTransactions_BridgeCorrectly {
|
|
||||||
|
|
||||||
CSDataStack *dataStack = [[CSDataStack alloc]
|
|
||||||
initWithXcodeModelName:@"Model"
|
|
||||||
bundle:[NSBundle bundleForClass:[self class]]
|
|
||||||
versionChain:nil];
|
|
||||||
XCTAssertNotNil(dataStack);
|
|
||||||
|
|
||||||
[dataStack
|
|
||||||
addInMemoryStorageAndWait:[CSInMemoryStore new]
|
|
||||||
error:nil];
|
|
||||||
|
|
||||||
{
|
|
||||||
CSUnsafeDataTransaction *transaction = [dataStack beginUnsafe];
|
|
||||||
XCTAssertNotNil(transaction);
|
|
||||||
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
|
|
||||||
NSError *error;
|
|
||||||
BOOL result = [transaction commitAndWaitWithError:&error];
|
|
||||||
XCTAssertTrue(result);
|
|
||||||
XCTAssertNil(error);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
|
|
||||||
NSError *error;
|
|
||||||
BOOL result =
|
|
||||||
[dataStack
|
|
||||||
beginSynchronous:^(CSSynchronousDataTransaction * _Nonnull transaction) {
|
|
||||||
|
|
||||||
XCTAssertNotNil(transaction);
|
|
||||||
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
|
|
||||||
NSError *error;
|
|
||||||
XCTAssertTrue([transaction commitAndWaitWithError:&error]);
|
|
||||||
XCTAssertNil(error);
|
|
||||||
[expectation fulfill];
|
|
||||||
}
|
|
||||||
error:&error];
|
|
||||||
XCTAssertTrue(result);
|
|
||||||
XCTAssertNil(error);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
XCTestExpectation *expectation = [self expectationWithDescription:@"async"];
|
|
||||||
[dataStack beginAsynchronous:^(CSAsynchronousDataTransaction * _Nonnull transaction) {
|
|
||||||
|
|
||||||
XCTAssertNotNil(transaction);
|
|
||||||
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
|
|
||||||
[transaction
|
|
||||||
commitWithSuccess:^{
|
|
||||||
|
|
||||||
[expectation fulfill];
|
|
||||||
}
|
|
||||||
failure:^(CSError *error){
|
|
||||||
|
|
||||||
XCTFail();
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
[self waitForExpectationsWithTimeout:10 handler:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
//
|
|
||||||
// ConvenienceTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - ConvenienceTests
|
|
||||||
|
|
||||||
@available(macOS 10.12, *)
|
|
||||||
class ConvenienceTests: BaseTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDataStacks_CanCreateFetchedResultsControllers() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
let controller = stack.createFetchedResultsController(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testString)),
|
|
||||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
|
|
||||||
Tweak { $0.fetchLimit = 10 }
|
|
||||||
)
|
|
||||||
XCTAssertEqual(controller.managedObjectContext, stack.mainContext)
|
|
||||||
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
|
|
||||||
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
|
|
||||||
XCTAssertEqual(
|
|
||||||
controller.fetchRequest.sortDescriptors!,
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
|
||||||
)
|
|
||||||
XCTAssertEqual(
|
|
||||||
controller.fetchRequest.predicate,
|
|
||||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
|
||||||
)
|
|
||||||
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatUnsafeDataTransactions_CanCreateFetchedResultsControllers() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
withExtendedLifetime(stack.beginUnsafe()) { (transaction: UnsafeDataTransaction) in
|
|
||||||
|
|
||||||
let controller = transaction.createFetchedResultsController(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testString)),
|
|
||||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
|
|
||||||
Tweak { $0.fetchLimit = 10 }
|
|
||||||
)
|
|
||||||
XCTAssertEqual(controller.managedObjectContext, transaction.context)
|
|
||||||
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
|
|
||||||
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
|
|
||||||
XCTAssertEqual(
|
|
||||||
controller.fetchRequest.sortDescriptors!,
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
|
||||||
)
|
|
||||||
XCTAssertEqual(
|
|
||||||
controller.fetchRequest.predicate,
|
|
||||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
|
||||||
)
|
|
||||||
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
//
|
|
||||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "BridgingTests.h"
|
|
||||||
@@ -1,548 +0,0 @@
|
|||||||
//
|
|
||||||
// DynamicModelTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
#if os(macOS)
|
|
||||||
typealias Color = NSColor
|
|
||||||
|
|
||||||
#else
|
|
||||||
typealias Color = UIColor
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class Animal: CoreStoreObject {
|
|
||||||
|
|
||||||
@Field.Stored("species")
|
|
||||||
var species: String = "Swift"
|
|
||||||
|
|
||||||
@Field.Coded("color", coder: FieldCoders.NSCoding.self)
|
|
||||||
var color: Color? = .blue
|
|
||||||
|
|
||||||
@Field.Relationship("master")
|
|
||||||
var master: Person?
|
|
||||||
}
|
|
||||||
|
|
||||||
class Dog: Animal {
|
|
||||||
|
|
||||||
static let commonNicknames = ["Spot", "Benjie", "Max", "Milo"]
|
|
||||||
|
|
||||||
@Field.Stored(
|
|
||||||
"nickname",
|
|
||||||
dynamicInitialValue: {
|
|
||||||
commonNicknames.randomElement()!
|
|
||||||
}
|
|
||||||
)
|
|
||||||
var nickname: String
|
|
||||||
|
|
||||||
@Field.Stored("age")
|
|
||||||
var age: Int = 1
|
|
||||||
|
|
||||||
@Field.Relationship("friends")
|
|
||||||
var friends: [Dog]
|
|
||||||
|
|
||||||
@Field.Relationship("friendedBy", inverse: \.$friends)
|
|
||||||
var friendedBy: Set<Dog>
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomType {
|
|
||||||
var string = "customString"
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Job: String, CaseIterable {
|
|
||||||
|
|
||||||
case unemployed
|
|
||||||
case engineer
|
|
||||||
case doctor
|
|
||||||
case lawyer
|
|
||||||
|
|
||||||
init?(data: Data) {
|
|
||||||
|
|
||||||
guard
|
|
||||||
let rawValue = String(data: data, encoding: .utf8),
|
|
||||||
let value = Self.init(rawValue: rawValue)
|
|
||||||
else {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
self = value
|
|
||||||
}
|
|
||||||
|
|
||||||
func toData() -> Data {
|
|
||||||
|
|
||||||
return Data(self.rawValue.utf8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Person: CoreStoreObject {
|
|
||||||
|
|
||||||
@Field.Stored(
|
|
||||||
"title",
|
|
||||||
customSetter: { (object, field, newValue) in
|
|
||||||
field.primitiveValue = newValue
|
|
||||||
object.$displayName.primitiveValue = nil
|
|
||||||
}
|
|
||||||
)
|
|
||||||
var title: String = "Mr."
|
|
||||||
|
|
||||||
@Field.Stored(
|
|
||||||
"name",
|
|
||||||
customSetter: { (object, field, newValue) in
|
|
||||||
field.primitiveValue = newValue
|
|
||||||
object.$displayName.primitiveValue = nil
|
|
||||||
}
|
|
||||||
)
|
|
||||||
var name: String = ""
|
|
||||||
|
|
||||||
@Field.Virtual(
|
|
||||||
"displayName",
|
|
||||||
customGetter: Person.getDisplayName(_:_:),
|
|
||||||
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
|
|
||||||
)
|
|
||||||
var displayName: String?
|
|
||||||
|
|
||||||
@Field.Virtual(
|
|
||||||
"customType",
|
|
||||||
customGetter: { (object, field) in
|
|
||||||
|
|
||||||
if let value = field.primitiveValue {
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
let value = CustomType()
|
|
||||||
field.primitiveValue = value
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
var customField: CustomType
|
|
||||||
|
|
||||||
@Field.Coded(
|
|
||||||
"job",
|
|
||||||
coder: (
|
|
||||||
encode: { $0.toData() },
|
|
||||||
decode: { $0.flatMap(Job.init(data:)) ?? .unemployed }
|
|
||||||
),
|
|
||||||
dynamicInitialValue: {
|
|
||||||
Job.allCases.randomElement()!
|
|
||||||
}
|
|
||||||
)
|
|
||||||
var job: Job
|
|
||||||
|
|
||||||
@Field.Relationship("spouse")
|
|
||||||
var spouse: Person?
|
|
||||||
|
|
||||||
@Field.Relationship("pets", inverse: \.$master)
|
|
||||||
var pets: Set<Animal>
|
|
||||||
|
|
||||||
@Field.Relationship("_spouseInverse", inverse: \.$spouse)
|
|
||||||
private var spouseInverse: Person?
|
|
||||||
|
|
||||||
private static func getDisplayName(_ object: ObjectProxy<Person>, _ field: ObjectProxy<Person>.FieldProxy<String?>) -> String? {
|
|
||||||
|
|
||||||
if let value = field.primitiveValue {
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
let title = object.$title.value
|
|
||||||
let name = object.$name.value
|
|
||||||
let value = "\(title) \(name)"
|
|
||||||
field.primitiveValue = value
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func keyPathsAffectingDisplayName() -> Set<String> {
|
|
||||||
|
|
||||||
return [
|
|
||||||
String(keyPath: \Person.$title),
|
|
||||||
String(keyPath: \Person.$name)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - DynamicModelTests
|
|
||||||
|
|
||||||
class DynamicModelTests: BaseTestDataTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDynamicModels_CanBeDeclaredCorrectly() {
|
|
||||||
|
|
||||||
let dataStack = DataStack(
|
|
||||||
CoreStoreSchema(
|
|
||||||
modelVersion: "V1",
|
|
||||||
entities: [
|
|
||||||
Entity<Animal>("Animal"),
|
|
||||||
Entity<Dog>("Dog"),
|
|
||||||
Entity<Person>("Person")
|
|
||||||
],
|
|
||||||
versionLock: [
|
|
||||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
|
||||||
"Dog": [0xad6de93adc5565d, 0x7897e51253eba5a3, 0xd12b9ce0b13600f3, 0x5a4827cd794cd15e],
|
|
||||||
"Person": [0xf3e6ba6016bbedc6, 0x50dedf64f0eba490, 0xa32088a0ee83468d, 0xb72d1d0b37bd0992]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
|
|
||||||
|
|
||||||
let k1 = String(keyPath: \Animal.$species)
|
|
||||||
XCTAssertEqual(k1, "species")
|
|
||||||
|
|
||||||
let k2 = String(keyPath: \Dog.$species)
|
|
||||||
XCTAssertEqual(k2, "species")
|
|
||||||
|
|
||||||
let k3 = String(keyPath: \Dog.$nickname)
|
|
||||||
XCTAssertEqual(k3, "nickname")
|
|
||||||
|
|
||||||
let updateDone = self.expectation(description: "update-done")
|
|
||||||
let fetchDone = self.expectation(description: "fetch-done")
|
|
||||||
let willSetPriorObserverDone = self.expectation(description: "willSet-observe-prior-done")
|
|
||||||
let willSetNotPriorObserverDone = self.expectation(description: "willSet-observe-notPrior-done")
|
|
||||||
let didSetObserverDone = self.expectation(description: "didSet-observe-done")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) in
|
|
||||||
|
|
||||||
let animal = transaction.create(Into<Animal>())
|
|
||||||
XCTAssertEqual(animal.species, "Swift")
|
|
||||||
XCTAssertTrue(type(of: animal.species) == String.self)
|
|
||||||
XCTAssertEqual(animal.color, Color.blue)
|
|
||||||
|
|
||||||
animal.species = "Sparrow"
|
|
||||||
XCTAssertEqual(animal.species, "Sparrow")
|
|
||||||
|
|
||||||
animal.color = .yellow
|
|
||||||
XCTAssertEqual(animal.color, Color.yellow)
|
|
||||||
|
|
||||||
for property in Animal.metaProperties(includeSuperclasses: true) {
|
|
||||||
|
|
||||||
switch property.keyPath {
|
|
||||||
|
|
||||||
case String(keyPath: \Animal.$species):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
|
|
||||||
|
|
||||||
case String(keyPath: \Animal.$master):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Relationship<Person?>)
|
|
||||||
|
|
||||||
case String(keyPath: \Animal.$color):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let dog = transaction.create(Into<Dog>())
|
|
||||||
XCTAssertEqual(dog.species, "Swift")
|
|
||||||
XCTAssertEqual(dog.age, 1)
|
|
||||||
XCTAssertTrue(Dog.commonNicknames.contains(dog.nickname))
|
|
||||||
|
|
||||||
for property in Dog.metaProperties(includeSuperclasses: true) {
|
|
||||||
|
|
||||||
switch property.keyPath {
|
|
||||||
|
|
||||||
case String(keyPath: \Dog.$species):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
|
|
||||||
|
|
||||||
case String(keyPath: \Dog.$master):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Relationship<Person?>)
|
|
||||||
|
|
||||||
case String(keyPath: \Dog.$color):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
|
|
||||||
|
|
||||||
case String(keyPath: \Dog.$nickname):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Dog>.Stored<String>)
|
|
||||||
|
|
||||||
case String(keyPath: \Dog.$age):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Dog>.Stored<Int>)
|
|
||||||
|
|
||||||
case String(keyPath: \Dog.$friends):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<[Dog]>)
|
|
||||||
|
|
||||||
case String(keyPath: \Dog.$friendedBy):
|
|
||||||
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<Set<Dog>>)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// #if swift(>=5.1)
|
|
||||||
//
|
|
||||||
// let dogKeyPathBuilder = Dog.keyPathBuilder()
|
|
||||||
// XCTAssertEqual(dogKeyPathBuilder.species.keyPathString, "SELF.species")
|
|
||||||
// XCTAssertEqual(dogKeyPathBuilder.master.title.keyPathString, "SELF.master.title")
|
|
||||||
// let a = dogKeyPathBuilder.master
|
|
||||||
// let b = dogKeyPathBuilder.master.spouse
|
|
||||||
// let c = dogKeyPathBuilder.master.spouse.pets
|
|
||||||
// let d = dogKeyPathBuilder.master.spouse.pets.color
|
|
||||||
// XCTAssertEqual(dogKeyPathBuilder.master.spouse.pets.color.keyPathString, "SELF.master.spouse.pets.color")
|
|
||||||
//
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
let didSetObserver = dog.observe(\.$species, options: [.new, .old]) { (object, change) in
|
|
||||||
|
|
||||||
XCTAssertEqual(object, dog)
|
|
||||||
XCTAssertEqual(change.kind, .setting)
|
|
||||||
XCTAssertEqual(change.newValue, "Dog")
|
|
||||||
XCTAssertEqual(change.oldValue, "Swift")
|
|
||||||
XCTAssertFalse(change.isPrior)
|
|
||||||
XCTAssertEqual(object.species, "Dog")
|
|
||||||
didSetObserverDone.fulfill()
|
|
||||||
}
|
|
||||||
let willSetObserver = dog.observe(\.$species, options: [.new, .old, .prior]) { (object, change) in
|
|
||||||
|
|
||||||
XCTAssertEqual(object, dog)
|
|
||||||
XCTAssertEqual(change.kind, .setting)
|
|
||||||
XCTAssertEqual(change.oldValue, "Swift")
|
|
||||||
|
|
||||||
if change.isPrior {
|
|
||||||
|
|
||||||
XCTAssertNil(change.newValue)
|
|
||||||
XCTAssertEqual(object.species, "Swift")
|
|
||||||
willSetPriorObserverDone.fulfill()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTAssertEqual(change.newValue, "Dog")
|
|
||||||
XCTAssertEqual(object.species, "Dog")
|
|
||||||
willSetNotPriorObserverDone.fulfill()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dog.species = "Dog"
|
|
||||||
XCTAssertEqual(dog.species, "Dog")
|
|
||||||
|
|
||||||
didSetObserver.invalidate()
|
|
||||||
willSetObserver.invalidate()
|
|
||||||
|
|
||||||
dog.nickname = "Spot"
|
|
||||||
XCTAssertEqual(dog.nickname, "Spot")
|
|
||||||
|
|
||||||
let person = transaction.create(Into<Person>())
|
|
||||||
XCTAssertTrue(person.pets.isEmpty)
|
|
||||||
XCTAssertEqual(person.customField.string, "customString")
|
|
||||||
let initialJob = person.job
|
|
||||||
XCTAssertTrue(Job.allCases.contains(initialJob))
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
person.rawObject!
|
|
||||||
.runtimeType()
|
|
||||||
.keyPathsForValuesAffectingValue(forKey: "displayName"),
|
|
||||||
["title", "name"]
|
|
||||||
)
|
|
||||||
|
|
||||||
person.name = "Joe"
|
|
||||||
|
|
||||||
XCTAssertEqual(person.rawObject!.value(forKey: "name") as! String?, "Joe")
|
|
||||||
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "Mr. Joe")
|
|
||||||
|
|
||||||
person.rawObject!.setValue("AAAA", forKey: "displayName")
|
|
||||||
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "AAAA")
|
|
||||||
|
|
||||||
person.name = "John"
|
|
||||||
XCTAssertEqual(person.name, "John")
|
|
||||||
XCTAssertEqual(person.displayName, "Mr. John") // Custom getter
|
|
||||||
|
|
||||||
let personSnapshot1 = person.asSnapshot(in: transaction)!
|
|
||||||
XCTAssertEqual(person.name, personSnapshot1.$name)
|
|
||||||
XCTAssertEqual(person.title, personSnapshot1.$title)
|
|
||||||
XCTAssertEqual(person.displayName, personSnapshot1.$displayName)
|
|
||||||
XCTAssertEqual(person.job, personSnapshot1.$job)
|
|
||||||
|
|
||||||
person.title = "Sir"
|
|
||||||
XCTAssertEqual(person.displayName, "Sir John")
|
|
||||||
|
|
||||||
XCTAssertEqual(personSnapshot1.$name, "John")
|
|
||||||
XCTAssertEqual(personSnapshot1.$title, "Mr.")
|
|
||||||
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
|
|
||||||
|
|
||||||
person.customField.string = "newCustomString"
|
|
||||||
XCTAssertEqual(person.customField.string, "newCustomString")
|
|
||||||
|
|
||||||
person.job = .engineer
|
|
||||||
XCTAssertEqual(person.job, .engineer)
|
|
||||||
|
|
||||||
let personSnapshot2 = person.asSnapshot(in: transaction)!
|
|
||||||
XCTAssertEqual(person.name, personSnapshot2.$name)
|
|
||||||
XCTAssertEqual(person.title, personSnapshot2.$title)
|
|
||||||
XCTAssertEqual(person.displayName, personSnapshot2.$displayName)
|
|
||||||
XCTAssertEqual(person.job, personSnapshot2.$job)
|
|
||||||
|
|
||||||
var personSnapshot3 = personSnapshot2
|
|
||||||
personSnapshot3.$name = "James"
|
|
||||||
XCTAssertEqual(personSnapshot1.$name, "John")
|
|
||||||
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
|
|
||||||
XCTAssertEqual(personSnapshot1.$job, initialJob)
|
|
||||||
XCTAssertEqual(personSnapshot2.$name, "John")
|
|
||||||
XCTAssertEqual(personSnapshot2.$displayName, "Sir John")
|
|
||||||
XCTAssertEqual(personSnapshot2.$job, .engineer)
|
|
||||||
XCTAssertEqual(personSnapshot3.$name, "James")
|
|
||||||
XCTAssertEqual(personSnapshot3.$displayName, "Sir John")
|
|
||||||
XCTAssertEqual(personSnapshot3.$job, .engineer)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
person.pets.insert(dog)
|
|
||||||
XCTAssertEqual(person.pets.count, 1)
|
|
||||||
XCTAssertEqual(person.pets.first, dog)
|
|
||||||
XCTAssertEqual(person.pets.first?.master, person)
|
|
||||||
XCTAssertEqual(dog.master, person)
|
|
||||||
XCTAssertEqual(dog.master?.pets.first, dog)
|
|
||||||
},
|
|
||||||
success: { _ in
|
|
||||||
|
|
||||||
let person = try! stack.fetchOne(From<Person>())
|
|
||||||
XCTAssertNotNil(person)
|
|
||||||
|
|
||||||
let personPublisher = person!.asPublisher(in: stack)
|
|
||||||
XCTAssertEqual(personPublisher.$name, "John")
|
|
||||||
XCTAssertEqual(personPublisher.$displayName, "Sir John")
|
|
||||||
XCTAssertEqual(personPublisher.$job, .engineer)
|
|
||||||
|
|
||||||
updateDone.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) in
|
|
||||||
|
|
||||||
let p1 = Where<Animal>({ $0.$species == "Sparrow" })
|
|
||||||
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
|
|
||||||
|
|
||||||
let bird = try transaction.fetchOne(From<Animal>(), p1)
|
|
||||||
XCTAssertNotNil(bird)
|
|
||||||
XCTAssertEqual(bird!.species, "Sparrow")
|
|
||||||
XCTAssertEqual(bird!.color, Color.yellow)
|
|
||||||
|
|
||||||
let p2 = Where<Dog>({ $0.$nickname == "Spot" })
|
|
||||||
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
|
|
||||||
|
|
||||||
let dog = try transaction.fetchOne(From<Dog>().where(\.$nickname == "Spot"))
|
|
||||||
XCTAssertNotNil(dog)
|
|
||||||
XCTAssertEqual(dog!.nickname, "Spot")
|
|
||||||
XCTAssertEqual(dog!.species, "Dog")
|
|
||||||
|
|
||||||
let person = try transaction.fetchOne(From<Person>())
|
|
||||||
XCTAssertNotNil(person)
|
|
||||||
XCTAssertEqual(person!.name, "John")
|
|
||||||
XCTAssertEqual(person!.title, "Sir")
|
|
||||||
XCTAssertEqual(person!.displayName, "Sir John")
|
|
||||||
XCTAssertEqual(person!.customField.string, "customString")
|
|
||||||
XCTAssertEqual(person!.job, .engineer)
|
|
||||||
XCTAssertEqual(person!.pets.first, dog)
|
|
||||||
|
|
||||||
let p3 = Where<Dog>({ $0.$age == 10 })
|
|
||||||
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
|
|
||||||
|
|
||||||
let totalAge = try transaction.queryValue(
|
|
||||||
From<Dog>().select(Int.self, .sum(\.$age))
|
|
||||||
)
|
|
||||||
XCTAssertEqual(totalAge, 1)
|
|
||||||
|
|
||||||
_ = try transaction.fetchAll(
|
|
||||||
From<Dog>()
|
|
||||||
.where(\Animal.$species == "Dog" && \Dog.$age == 10)
|
|
||||||
)
|
|
||||||
_ = try transaction.fetchAll(
|
|
||||||
From<Dog>()
|
|
||||||
.where(\Dog.$age == 10 && \Animal.$species == "Dog")
|
|
||||||
.orderBy(.ascending({ $0.$species }))
|
|
||||||
)
|
|
||||||
_ = try transaction.fetchAll(
|
|
||||||
From<Dog>(),
|
|
||||||
Where<Dog>({ $0.$age > 10 && $0.$age <= 15 })
|
|
||||||
)
|
|
||||||
_ = try transaction.fetchAll(
|
|
||||||
From<Dog>(),
|
|
||||||
Where<Dog>({ $0.$species == "Dog" && $0.$age == 10 })
|
|
||||||
)
|
|
||||||
_ = try transaction.fetchAll(
|
|
||||||
From<Dog>(),
|
|
||||||
Where<Dog>({ $0.$age == 10 && $0.$species == "Dog" })
|
|
||||||
)
|
|
||||||
_ = try transaction.fetchAll(
|
|
||||||
From<Dog>(),
|
|
||||||
Where<Dog>({ $0.$age > 10 && $0.$age <= 15 })
|
|
||||||
)
|
|
||||||
_ = try transaction.fetchAll(
|
|
||||||
From<Dog>(),
|
|
||||||
(\Dog.$age > 10 && \Dog.$age <= 15)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
success: { _ in
|
|
||||||
|
|
||||||
fetchDone.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.waitForExpectations(timeout: 10, handler: { _ in })
|
|
||||||
|
|
||||||
self.addTeardownBlock {
|
|
||||||
dataStack.unsafeRemoveAllPersistentStoresAndWait()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
|
|
||||||
|
|
||||||
XCTAssertEqual(String(keyPath: \Animal.$species), "species")
|
|
||||||
XCTAssertEqual(String(keyPath: \Dog.$species), "species")
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc
|
|
||||||
func prepareStack(_ dataStack: DataStack, configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> Void) {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
try configurations.forEach { (configuration) in
|
|
||||||
|
|
||||||
try dataStack.addStorageAndWait(
|
|
||||||
SQLiteStore(
|
|
||||||
fileURL: SQLiteStore.defaultRootDirectory
|
|
||||||
.appendingPathComponent(UUID().uuidString)
|
|
||||||
.appendingPathComponent("\(Self.self)_\((configuration ?? "-null-")).sqlite"),
|
|
||||||
configuration: configuration,
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.coreStoreDumpString)
|
|
||||||
}
|
|
||||||
closure(dataStack)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
//
|
|
||||||
// ErrorTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - ErrorTests
|
|
||||||
|
|
||||||
@available(*, deprecated, message: "CoreStore Objective-C API will be removed soon.")
|
|
||||||
final class ErrorTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatUnknownErrors_BridgeCorrectly() {
|
|
||||||
|
|
||||||
let error = CoreStoreError.unknown
|
|
||||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.unknownError.rawValue)
|
|
||||||
|
|
||||||
let userInfo: NSDictionary = [:]
|
|
||||||
|
|
||||||
let objcError = error.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.unknownError.rawValue)
|
|
||||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
|
||||||
|
|
||||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.unknownError.rawValue)
|
|
||||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() {
|
|
||||||
|
|
||||||
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
|
|
||||||
|
|
||||||
let error = CoreStoreError.differentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
|
|
||||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
|
|
||||||
|
|
||||||
let userInfo: NSDictionary = [
|
|
||||||
"existingPersistentStoreURL": dummyURL
|
|
||||||
]
|
|
||||||
let objcError = error.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
|
|
||||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
|
||||||
|
|
||||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
|
|
||||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() {
|
|
||||||
|
|
||||||
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
|
|
||||||
|
|
||||||
let schemaHistory = SchemaHistory(
|
|
||||||
XcodeDataModelSchema.from(
|
|
||||||
modelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
let version = "1.0.0"
|
|
||||||
|
|
||||||
let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: schemaHistory.rawModel, targetModelVersion: version)
|
|
||||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
|
|
||||||
|
|
||||||
let userInfo: NSDictionary = [
|
|
||||||
"localStoreURL": dummyURL,
|
|
||||||
"targetModel": schemaHistory.rawModel,
|
|
||||||
"targetModelVersion": version
|
|
||||||
]
|
|
||||||
let objcError = error.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
|
|
||||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
|
||||||
|
|
||||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
|
|
||||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() {
|
|
||||||
|
|
||||||
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
|
|
||||||
|
|
||||||
let error = CoreStoreError.progressiveMigrationRequired(localStoreURL: dummyURL)
|
|
||||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
|
|
||||||
|
|
||||||
let userInfo: NSDictionary = [
|
|
||||||
"localStoreURL": dummyURL
|
|
||||||
]
|
|
||||||
let objcError = error.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
|
|
||||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
|
||||||
|
|
||||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
|
|
||||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatInternalErrorErrors_BridgeCorrectly() {
|
|
||||||
|
|
||||||
let internalError = NSError(
|
|
||||||
domain: "com.dummy",
|
|
||||||
code: 123,
|
|
||||||
userInfo: [
|
|
||||||
"key1": "value1",
|
|
||||||
"key2": 2,
|
|
||||||
"key3": Date()
|
|
||||||
]
|
|
||||||
)
|
|
||||||
let error = CoreStoreError(internalError)
|
|
||||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.internalError.rawValue)
|
|
||||||
|
|
||||||
let userInfo: NSDictionary = [
|
|
||||||
"NSError": internalError
|
|
||||||
]
|
|
||||||
let objcError = error.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.internalError.rawValue)
|
|
||||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
|
||||||
|
|
||||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
|
||||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
|
||||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.internalError.rawValue)
|
|
||||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,418 +0,0 @@
|
|||||||
//
|
|
||||||
// FromTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - FromTests
|
|
||||||
|
|
||||||
final class FromTests: BaseTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFromClauses_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<NSManagedObject>()
|
|
||||||
XCTAssert(from.entityClass === NSManagedObject.self)
|
|
||||||
XCTAssertNil(from.configurations)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>()
|
|
||||||
XCTAssert(from.entityClass === TestEntity1.self)
|
|
||||||
XCTAssertNil(from.configurations)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config1")
|
|
||||||
XCTAssert(from.entityClass === TestEntity1.self)
|
|
||||||
XCTAssertEqual(from.configurations?.count, 1)
|
|
||||||
XCTAssertEqual(from.configurations?[0], "Config1")
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>(nil, "Config1")
|
|
||||||
XCTAssert(from.entityClass === TestEntity1.self)
|
|
||||||
XCTAssertEqual(from.configurations?.count, 2)
|
|
||||||
XCTAssertEqual(from.configurations?[0], nil)
|
|
||||||
XCTAssertEqual(from.configurations?[1], "Config1")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForDefaultConfigurations() {
|
|
||||||
|
|
||||||
self.prepareStack { (dataStack) in
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>()
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config1")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForSingleConfigurations() {
|
|
||||||
|
|
||||||
self.prepareStack(configurations: ["Config1"]) { (dataStack) in
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>()
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config1")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config2")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>()
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>("Config1")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>("Config2")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForDefaultAndCustomConfigurations() {
|
|
||||||
|
|
||||||
self.prepareStack(configurations: [nil, "Config1"]) { (dataStack) in
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>()
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config1")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config2")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>()
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>("Config1")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>("Config2")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForMultipleConfigurations() {
|
|
||||||
|
|
||||||
self.prepareStack(configurations: ["Config1", "Config2"]) { (dataStack) in
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>()
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config1")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity1>("Config2")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>()
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["Config2"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>("Config1")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
self.expectError(code: .persistentStoreNotFound) {
|
|
||||||
|
|
||||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
}
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let from = From<TestEntity2>("Config2")
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
XCTAssertNotNil(storesFound)
|
|
||||||
XCTAssertNotNil(request.entity)
|
|
||||||
XCTAssertNotNil(request.safeAffectedStores())
|
|
||||||
|
|
||||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
|
||||||
|
|
||||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
|
||||||
XCTAssertEqual(affectedConfigurations, ["Config2"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
//
|
|
||||||
// GroupByTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - GroupByTests
|
|
||||||
|
|
||||||
final class GroupByTests: BaseTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatGroupByClauses_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let groupBy = GroupBy<NSManagedObject>()
|
|
||||||
XCTAssertEqual(groupBy, GroupBy([] as [String]))
|
|
||||||
XCTAssertNotEqual(groupBy, GroupBy("key"))
|
|
||||||
XCTAssertTrue(groupBy.keyPaths.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let groupBy = GroupBy<NSManagedObject>("key1")
|
|
||||||
XCTAssertEqual(groupBy, GroupBy("key1"))
|
|
||||||
XCTAssertEqual(groupBy, GroupBy(["key1"]))
|
|
||||||
XCTAssertNotEqual(groupBy, GroupBy("key2"))
|
|
||||||
XCTAssertEqual(groupBy.keyPaths, ["key1"])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let groupBy = GroupBy<NSManagedObject>("key1", "key2")
|
|
||||||
XCTAssertEqual(groupBy, GroupBy("key1", "key2"))
|
|
||||||
XCTAssertEqual(groupBy, GroupBy(["key1", "key2"]))
|
|
||||||
XCTAssertNotEqual(groupBy, GroupBy("key2", "key1"))
|
|
||||||
XCTAssertEqual(groupBy.keyPaths, ["key1", "key2"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatGroupByClauses_ApplyToFetchRequestsCorrectly() {
|
|
||||||
|
|
||||||
self.prepareStack { (dataStack) in
|
|
||||||
|
|
||||||
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
|
|
||||||
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
try From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
|
|
||||||
groupBy.applyToFetchRequest(request)
|
|
||||||
|
|
||||||
XCTAssertNotNil(request.propertiesToGroupBy)
|
|
||||||
|
|
||||||
let attributes = (request.propertiesToGroupBy ?? []) as! [NSAttributeDescription]
|
|
||||||
XCTAssertEqual(attributes.map { $0.name }, groupBy.keyPaths)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?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>en</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>6.2.1</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
//
|
|
||||||
// IntoTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - IntoTests
|
|
||||||
|
|
||||||
final class IntoTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatIntoClauseConstants_AreCorrect() {
|
|
||||||
|
|
||||||
XCTAssertEqual(DataStack.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME")
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatIntoClauses_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into<NSManagedObject>()
|
|
||||||
XCTAssert(into.entityClass === NSManagedObject.self)
|
|
||||||
XCTAssertNil(into.configuration)
|
|
||||||
XCTAssertTrue(into.inferStoreIfPossible)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into<TestEntity1>()
|
|
||||||
XCTAssert(into.entityClass === TestEntity1.self)
|
|
||||||
XCTAssertNil(into.configuration)
|
|
||||||
XCTAssertTrue(into.inferStoreIfPossible)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into(TestEntity1.self)
|
|
||||||
XCTAssert(into.entityClass === TestEntity1.self)
|
|
||||||
XCTAssertNil(into.configuration)
|
|
||||||
XCTAssertTrue(into.inferStoreIfPossible)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into<TestEntity1>("Config1")
|
|
||||||
XCTAssert(into.entityClass === TestEntity1.self)
|
|
||||||
XCTAssertEqual(into.configuration, "Config1")
|
|
||||||
XCTAssertFalse(into.inferStoreIfPossible)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into(TestEntity1.self, "Config1")
|
|
||||||
XCTAssert(into.entityClass === TestEntity1.self)
|
|
||||||
XCTAssertEqual(into.configuration, "Config1")
|
|
||||||
XCTAssertFalse(into.inferStoreIfPossible)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatIntoClauses_AreEquatable() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into<NSManagedObject>()
|
|
||||||
XCTAssertEqual(into, Into<NSManagedObject>())
|
|
||||||
XCTAssertEqual(into, Into(NSManagedObject.self))
|
|
||||||
XCTAssertNotEqual(into, Into<NSManagedObject>(TestEntity1.self))
|
|
||||||
XCTAssertNotEqual(into, Into<NSManagedObject>("Config1"))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into<TestEntity1>()
|
|
||||||
XCTAssertEqual(into, Into<TestEntity1>())
|
|
||||||
XCTAssertEqual(into, Into(TestEntity1.self))
|
|
||||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into(TestEntity1.self)
|
|
||||||
XCTAssert(into == Into<TestEntity1>())
|
|
||||||
XCTAssertEqual(into, Into(TestEntity1.self))
|
|
||||||
XCTAssertFalse(into == Into<TestEntity1>("Config1"))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into<TestEntity1>("Config1")
|
|
||||||
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
|
|
||||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into(TestEntity1.self, "Config1")
|
|
||||||
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
|
|
||||||
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
|
|
||||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into(TestEntity1.self, "Config1")
|
|
||||||
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
|
|
||||||
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
|
|
||||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatIntoClauses_BridgeCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let into = Into<NSManagedObject>()
|
|
||||||
let objcInto = into.bridgeToObjectiveC
|
|
||||||
XCTAssertEqual(into, objcInto.bridgeToSwift)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,676 +0,0 @@
|
|||||||
//
|
|
||||||
// ListObserverTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - ListObserverTests
|
|
||||||
|
|
||||||
@available(macOS 10.12, *)
|
|
||||||
class ListObserverTests: BaseTestDataTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListObservers_CanReceiveInsertNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
let observer = TestListObserver()
|
|
||||||
let monitor = stack.monitorSectionedList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
monitor.addObserver(observer)
|
|
||||||
|
|
||||||
XCTAssertFalse(monitor.hasSections())
|
|
||||||
XCTAssertFalse(monitor.hasObjects())
|
|
||||||
XCTAssertTrue(monitor.objectsInAllSections().isEmpty)
|
|
||||||
|
|
||||||
var events = 0
|
|
||||||
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 0)
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 1)
|
|
||||||
XCTAssertEqual(
|
|
||||||
((note.userInfo as NSDictionary?) ?? [:]),
|
|
||||||
[
|
|
||||||
"sectionInfo": monitor.sectionInfo(at: 0),
|
|
||||||
"sectionIndex": 0
|
|
||||||
] as NSDictionary
|
|
||||||
)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 1
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 2)
|
|
||||||
|
|
||||||
let userInfo = note.userInfo
|
|
||||||
XCTAssertNotNil(userInfo)
|
|
||||||
XCTAssertEqual(
|
|
||||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
|
||||||
["indexPath", "object"]
|
|
||||||
)
|
|
||||||
|
|
||||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
|
||||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
|
|
||||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
|
||||||
|
|
||||||
let object = userInfo?["object"] as? TestEntity1
|
|
||||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
|
||||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
|
|
||||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
|
|
||||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
|
|
||||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
|
||||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 2
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 3
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
let object = transaction.create(Into<TestEntity1>())
|
|
||||||
object.testBoolean = NSNumber(value: true)
|
|
||||||
object.testNumber = NSNumber(value: 1)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "1")
|
|
||||||
object.testString = "nil:TestEntity1:1"
|
|
||||||
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
|
|
||||||
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListObservers_CanReceiveUpdateNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
let observer = TestListObserver()
|
|
||||||
let monitor = stack.monitorSectionedList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
monitor.addObserver(observer)
|
|
||||||
|
|
||||||
XCTAssertTrue(monitor.hasSections())
|
|
||||||
XCTAssertEqual(monitor.numberOfSections(), 2)
|
|
||||||
XCTAssertTrue(monitor.hasObjects())
|
|
||||||
XCTAssertTrue(monitor.hasObjects(in: 0))
|
|
||||||
XCTAssertEqual(monitor.numberOfObjects(in: 0), 2)
|
|
||||||
XCTAssertEqual(monitor.numberOfObjects(in: 1), 3)
|
|
||||||
|
|
||||||
var events = 0
|
|
||||||
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 0)
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssert(events == 1 || events == 2)
|
|
||||||
|
|
||||||
let userInfo = note.userInfo
|
|
||||||
XCTAssertNotNil(userInfo)
|
|
||||||
XCTAssertEqual(
|
|
||||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
|
||||||
["indexPath", "object"]
|
|
||||||
)
|
|
||||||
|
|
||||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
|
||||||
let object = userInfo?["object"] as? TestEntity1
|
|
||||||
|
|
||||||
switch object?.testEntityID {
|
|
||||||
|
|
||||||
case NSNumber(value: 101)?:
|
|
||||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
|
|
||||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
|
||||||
|
|
||||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
|
||||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
|
|
||||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
|
|
||||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
|
|
||||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
|
||||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
|
|
||||||
|
|
||||||
case NSNumber(value: 102)?:
|
|
||||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
|
|
||||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
|
||||||
|
|
||||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
|
|
||||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
|
|
||||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
|
|
||||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
|
|
||||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
|
||||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 1 || events == 2
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 3)
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 3
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
if let object = try transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: 11)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "11")
|
|
||||||
object.testString = "nil:TestEntity1:11"
|
|
||||||
object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
if let object = try transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: 22)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "22")
|
|
||||||
object.testString = "nil:TestEntity1:22"
|
|
||||||
object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListObservers_CanReceiveMoveNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
let observer = TestListObserver()
|
|
||||||
let monitor = stack.monitorSectionedList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
monitor.addObserver(observer)
|
|
||||||
|
|
||||||
var events = 0
|
|
||||||
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 0)
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 1)
|
|
||||||
|
|
||||||
let userInfo = note.userInfo
|
|
||||||
XCTAssertNotNil(userInfo)
|
|
||||||
XCTAssertEqual(
|
|
||||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
|
||||||
["fromIndexPath", "toIndexPath", "object"]
|
|
||||||
)
|
|
||||||
|
|
||||||
let fromIndexPath = userInfo?["fromIndexPath"] as? NSIndexPath
|
|
||||||
XCTAssertEqual(fromIndexPath?.index(atPosition: 0), 0)
|
|
||||||
XCTAssertEqual(fromIndexPath?.index(atPosition: 1), 0)
|
|
||||||
|
|
||||||
let toIndexPath = userInfo?["toIndexPath"] as? NSIndexPath
|
|
||||||
XCTAssertEqual(toIndexPath?.index(atPosition: 0), 1)
|
|
||||||
XCTAssertEqual(toIndexPath?.index(atPosition: 1), 1)
|
|
||||||
|
|
||||||
let object = userInfo?["object"] as? TestEntity1
|
|
||||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
|
|
||||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
|
||||||
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 1
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 2)
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 2
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
if let object = try transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
|
||||||
|
|
||||||
object.testBoolean = NSNumber(value: true)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListObservers_CanReceiveDeleteNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
let observer = TestListObserver()
|
|
||||||
let monitor = stack.monitorSectionedList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
monitor.addObserver(observer)
|
|
||||||
|
|
||||||
var events = 0
|
|
||||||
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 0)
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssert(events == 1 || events == 2)
|
|
||||||
|
|
||||||
let userInfo = note.userInfo
|
|
||||||
XCTAssertNotNil(userInfo)
|
|
||||||
XCTAssertEqual(
|
|
||||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
|
||||||
["indexPath", "object"]
|
|
||||||
)
|
|
||||||
|
|
||||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
|
||||||
|
|
||||||
XCTAssertEqual(indexPath?.section, 0)
|
|
||||||
XCTAssert(indexPath?.index(atPosition: 1) == 0 || indexPath?.index(atPosition: 1) == 1)
|
|
||||||
|
|
||||||
let object = userInfo?["object"] as? TestEntity1
|
|
||||||
XCTAssertEqual(object?.isDeleted, true)
|
|
||||||
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 1 || events == 2
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 3)
|
|
||||||
|
|
||||||
let userInfo = note.userInfo
|
|
||||||
XCTAssertNotNil(userInfo)
|
|
||||||
XCTAssertEqual(
|
|
||||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
|
||||||
["sectionInfo", "sectionIndex"]
|
|
||||||
)
|
|
||||||
|
|
||||||
let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
|
|
||||||
XCTAssertNotNil(sectionInfo)
|
|
||||||
XCTAssertEqual(sectionInfo?.name, "0")
|
|
||||||
|
|
||||||
let sectionIndex = userInfo?["sectionIndex"]
|
|
||||||
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
|
|
||||||
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 3
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 4)
|
|
||||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 4
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
let count = try transaction.deleteAll(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
|
||||||
)
|
|
||||||
XCTAssertEqual(count, 2)
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: TestListObserver
|
|
||||||
|
|
||||||
@available(macOS 10.12, *)
|
|
||||||
class TestListObserver: ListSectionObserver {
|
|
||||||
|
|
||||||
// MARK: ListObserver
|
|
||||||
|
|
||||||
typealias ListEntityType = TestEntity1
|
|
||||||
|
|
||||||
func listMonitorWillChange(_ monitor: ListMonitor<TestEntity1>) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitorWillChange:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [:]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitorDidChange:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [:]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [:]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [:]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: ListObjectObserver
|
|
||||||
|
|
||||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"object": object,
|
|
||||||
"indexPath": indexPath
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: IndexPath) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"object": object,
|
|
||||||
"indexPath": indexPath
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: IndexPath) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"object": object,
|
|
||||||
"indexPath": indexPath
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"object": object,
|
|
||||||
"fromIndexPath": fromIndexPath,
|
|
||||||
"toIndexPath": toIndexPath
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: ListSectionObserver
|
|
||||||
|
|
||||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"sectionInfo": sectionInfo,
|
|
||||||
"sectionIndex": sectionIndex
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"sectionInfo": sectionInfo,
|
|
||||||
"sectionIndex": sectionIndex
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
//
|
|
||||||
// ListPublisherTests.swift
|
|
||||||
// CoreStore iOS
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if canImport(UIKit) || canImport(AppKit)
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - ListPublisherTests
|
|
||||||
|
|
||||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
|
|
||||||
class ListPublisherTests: BaseTestDataTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListPublishers_CanReceiveInsertNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
let observer = NSObject()
|
|
||||||
let listPublisher = stack.publishList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
XCTAssertFalse(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertFalse(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.itemIDs.isEmpty)
|
|
||||||
|
|
||||||
let didChangeExpectation = self.expectation(description: "didChange")
|
|
||||||
listPublisher.addObserver(observer) { listPublisher in
|
|
||||||
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 1)
|
|
||||||
|
|
||||||
didChangeExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
let object = transaction.create(Into<TestEntity1>())
|
|
||||||
object.testBoolean = NSNumber(value: true)
|
|
||||||
object.testNumber = NSNumber(value: 1)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "1")
|
|
||||||
object.testString = "nil:TestEntity1:1"
|
|
||||||
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
|
|
||||||
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
|
|
||||||
withExtendedLifetime(listPublisher, {})
|
|
||||||
withExtendedLifetime(observer, {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListPublishers_CanReceiveUpdateNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
let observer = NSObject()
|
|
||||||
let listPublisher = stack.publishList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
|
|
||||||
|
|
||||||
let didChangeExpectation = self.expectation(description: "didChange")
|
|
||||||
listPublisher.addObserver(observer) { listPublisher in
|
|
||||||
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
|
|
||||||
|
|
||||||
didChangeExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
if let object = try transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: 11)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "11")
|
|
||||||
object.testString = "nil:TestEntity1:11"
|
|
||||||
object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
if let object = try transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: 22)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "22")
|
|
||||||
object.testString = "nil:TestEntity1:22"
|
|
||||||
object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
|
|
||||||
withExtendedLifetime(listPublisher, {})
|
|
||||||
withExtendedLifetime(observer, {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListPublishers_CanReceiveMoveNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
let observer = NSObject()
|
|
||||||
let listPublisher = stack.publishList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
|
|
||||||
|
|
||||||
let didChangeExpectation = self.expectation(description: "didChange")
|
|
||||||
listPublisher.addObserver(observer) { listPublisher in
|
|
||||||
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 1)
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 4)
|
|
||||||
|
|
||||||
didChangeExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
if let object = try transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
|
||||||
|
|
||||||
object.testBoolean = NSNumber(value: true)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
|
|
||||||
withExtendedLifetime(listPublisher, {})
|
|
||||||
withExtendedLifetime(observer, {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatListPublishers_CanReceiveDeleteNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
let observer = NSObject()
|
|
||||||
let listPublisher = stack.publishList(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
|
||||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
|
||||||
)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
|
|
||||||
|
|
||||||
let didChangeExpectation = self.expectation(description: "didChange")
|
|
||||||
listPublisher.addObserver(observer) { listPublisher in
|
|
||||||
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasSections())
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 1)
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems())
|
|
||||||
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
|
|
||||||
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 3)
|
|
||||||
|
|
||||||
didChangeExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
let count = try transaction.deleteAll(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
|
||||||
)
|
|
||||||
XCTAssertEqual(count, 2)
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
//
|
|
||||||
// MigrationChainTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - MigrationChainTests
|
|
||||||
|
|
||||||
final class MigrationChainTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatNilMigrationChains_HaveNoVersions() {
|
|
||||||
|
|
||||||
let chain: MigrationChain = nil
|
|
||||||
XCTAssertTrue(chain.isValid)
|
|
||||||
XCTAssertTrue(chain.isEmpty)
|
|
||||||
|
|
||||||
XCTAssertFalse(chain.contains("version1"))
|
|
||||||
XCTAssertNil(chain.nextVersionFrom("version1"))
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatStringMigrationChains_HaveOneVersion() {
|
|
||||||
|
|
||||||
let chain: MigrationChain = "version1"
|
|
||||||
XCTAssertTrue(chain.isValid)
|
|
||||||
XCTAssertTrue(chain.isEmpty)
|
|
||||||
|
|
||||||
XCTAssertTrue(chain.contains("version1"))
|
|
||||||
XCTAssertFalse(chain.contains("version2"))
|
|
||||||
|
|
||||||
XCTAssertNil(chain.nextVersionFrom("version1"))
|
|
||||||
XCTAssertNil(chain.nextVersionFrom("version2"))
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatArrayMigrationChains_HaveLinearVersions() {
|
|
||||||
|
|
||||||
let chain: MigrationChain = ["version1", "version2", "version3", "version4"]
|
|
||||||
XCTAssertTrue(chain.isValid)
|
|
||||||
XCTAssertFalse(chain.isEmpty)
|
|
||||||
|
|
||||||
XCTAssertTrue(chain.contains("version1"))
|
|
||||||
XCTAssertTrue(chain.contains("version2"))
|
|
||||||
XCTAssertTrue(chain.contains("version3"))
|
|
||||||
XCTAssertTrue(chain.contains("version4"))
|
|
||||||
XCTAssertFalse(chain.contains("version5"))
|
|
||||||
|
|
||||||
XCTAssertEqual(chain.nextVersionFrom("version1"), "version2")
|
|
||||||
XCTAssertEqual(chain.nextVersionFrom("version2"), "version3")
|
|
||||||
XCTAssertEqual(chain.nextVersionFrom("version3"), "version4")
|
|
||||||
XCTAssertNil(chain.nextVersionFrom("version4"))
|
|
||||||
XCTAssertNil(chain.nextVersionFrom("version5"))
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDictionaryMigrationChains_HaveTreeVersions() {
|
|
||||||
|
|
||||||
let chain: MigrationChain = [
|
|
||||||
"version1": "version4",
|
|
||||||
"version2": "version3",
|
|
||||||
"version3": "version4"
|
|
||||||
]
|
|
||||||
XCTAssertTrue(chain.isValid)
|
|
||||||
XCTAssertFalse(chain.isEmpty)
|
|
||||||
|
|
||||||
XCTAssertTrue(chain.contains("version1"))
|
|
||||||
XCTAssertTrue(chain.contains("version2"))
|
|
||||||
XCTAssertTrue(chain.contains("version3"))
|
|
||||||
XCTAssertTrue(chain.contains("version4"))
|
|
||||||
XCTAssertFalse(chain.contains("version5"))
|
|
||||||
|
|
||||||
XCTAssertEqual(chain.nextVersionFrom("version1"), "version4")
|
|
||||||
XCTAssertEqual(chain.nextVersionFrom("version2"), "version3")
|
|
||||||
XCTAssertEqual(chain.nextVersionFrom("version3"), "version4")
|
|
||||||
XCTAssertNil(chain.nextVersionFrom("version4"))
|
|
||||||
XCTAssertNil(chain.nextVersionFrom("version5"))
|
|
||||||
|
|
||||||
// The cases below will trigger assertion failures internally
|
|
||||||
|
|
||||||
// let linearLoopChain: MigrationChain = ["version1", "version2", "version1", "version3", "version4"]
|
|
||||||
// XCTAssertFalse(linearLoopChain.valid, "linearLoopChain.valid")
|
|
||||||
//
|
|
||||||
// let treeAmbiguousChain: MigrationChain = [
|
|
||||||
// "version1": "version4",
|
|
||||||
// "version2": "version3",
|
|
||||||
// "version1": "version2",
|
|
||||||
// "version3": "version4"
|
|
||||||
// ]
|
|
||||||
// XCTAssertFalse(treeAmbiguousChain.valid, "treeAmbiguousChain.valid")
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatMigrationChains_AreEquatable() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let chain1: MigrationChain = nil
|
|
||||||
let chain2: MigrationChain = []
|
|
||||||
let chain3: MigrationChain = [:]
|
|
||||||
XCTAssertEqual(chain1, chain2)
|
|
||||||
XCTAssertEqual(chain2, chain3)
|
|
||||||
XCTAssertEqual(chain3, chain1)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let chain1: MigrationChain = "version1"
|
|
||||||
let chain2: MigrationChain = ["version1"]
|
|
||||||
XCTAssertEqual(chain1, chain2)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let chain1: MigrationChain = ["version1", "version2", "version3", "version4"]
|
|
||||||
let chain2: MigrationChain = [
|
|
||||||
"version1": "version2",
|
|
||||||
"version2": "version3",
|
|
||||||
"version3": "version4"
|
|
||||||
]
|
|
||||||
XCTAssertEqual(chain1, chain2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14460.32" systemVersion="17G2307" minimumToolsVersion="Xcode 4.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
|
|
||||||
<entity name="TestEntity1AAA" representedClassName="CoreStoreTests.TestEntity1" syncable="YES">
|
|
||||||
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
|
|
||||||
<attribute name="testDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
|
|
||||||
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
|
|
||||||
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
|
|
||||||
<relationship name="testToManyUnordered" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToOne" inverseEntity="TestEntity1AAA" syncable="YES"/>
|
|
||||||
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToManyUnordered" inverseEntity="TestEntity1AAA" syncable="YES"/>
|
|
||||||
</entity>
|
|
||||||
<entity name="TestEntity2" representedClassName="CoreStoreTests.TestEntity2" syncable="YES">
|
|
||||||
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
|
|
||||||
<attribute name="testDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
|
|
||||||
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
|
|
||||||
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
|
|
||||||
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
|
|
||||||
<relationship name="testToManyOrdered" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TestEntity2" inverseName="testToOne" inverseEntity="TestEntity2" syncable="YES"/>
|
|
||||||
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity2" inverseName="testToManyOrdered" inverseEntity="TestEntity2" syncable="YES"/>
|
|
||||||
</entity>
|
|
||||||
<configuration name="Config1">
|
|
||||||
<memberEntity name="TestEntity1AAA"/>
|
|
||||||
</configuration>
|
|
||||||
<configuration name="Config2">
|
|
||||||
<memberEntity name="TestEntity2"/>
|
|
||||||
</configuration>
|
|
||||||
<elements>
|
|
||||||
<element name="TestEntity1AAA" positionX="-63" positionY="-18" width="128" height="195"/>
|
|
||||||
<element name="TestEntity2" positionX="-63" positionY="9" width="128" height="195"/>
|
|
||||||
</elements>
|
|
||||||
</model>
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
//
|
|
||||||
// ObjectObserverTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - ObjectObserverTests
|
|
||||||
|
|
||||||
@available(macOS 10.12, *)
|
|
||||||
class ObjectObserverTests: BaseTestDataTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatObjectObservers_CanReceiveUpdateNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
guard let object = try stack.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let observer = TestObjectObserver()
|
|
||||||
let monitor = stack.monitorObject(object)
|
|
||||||
monitor.addObserver(observer)
|
|
||||||
|
|
||||||
XCTAssertEqual(monitor.object, object)
|
|
||||||
XCTAssertFalse(monitor.isObjectDeleted)
|
|
||||||
|
|
||||||
var events = 0
|
|
||||||
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 0)
|
|
||||||
XCTAssertEqual(
|
|
||||||
((note.userInfo as NSDictionary?) ?? [:]),
|
|
||||||
["object": object] as NSDictionary
|
|
||||||
)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 1)
|
|
||||||
XCTAssertEqual(
|
|
||||||
((note.userInfo as NSDictionary?) ?? [:]),
|
|
||||||
[
|
|
||||||
"object": object,
|
|
||||||
"changedPersistentKeys": Set(
|
|
||||||
[
|
|
||||||
#keyPath(TestEntity1.testNumber),
|
|
||||||
#keyPath(TestEntity1.testString)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
] as NSDictionary
|
|
||||||
)
|
|
||||||
let object = note.userInfo?["object"] as? TestEntity1
|
|
||||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 10))
|
|
||||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:10")
|
|
||||||
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 1
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
guard let object = transaction.edit(object) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
try transaction.cancel()
|
|
||||||
}
|
|
||||||
object.testNumber = NSNumber(value: 10)
|
|
||||||
object.testString = "nil:TestEntity1:10"
|
|
||||||
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatObjectObservers_CanReceiveDeleteNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
guard let object = try stack.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let observer = TestObjectObserver()
|
|
||||||
let monitor = stack.monitorObject(object)
|
|
||||||
monitor.addObserver(observer)
|
|
||||||
|
|
||||||
XCTAssertEqual(monitor.object, object)
|
|
||||||
XCTAssertFalse(monitor.isObjectDeleted)
|
|
||||||
|
|
||||||
var events = 0
|
|
||||||
|
|
||||||
_ = self.expectation(
|
|
||||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
|
|
||||||
object: observer,
|
|
||||||
handler: { (note) -> Bool in
|
|
||||||
|
|
||||||
XCTAssertEqual(events, 0)
|
|
||||||
XCTAssertEqual(
|
|
||||||
((note.userInfo as NSDictionary?) ?? [:]),
|
|
||||||
["object": object] as NSDictionary
|
|
||||||
)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
events += 1
|
|
||||||
}
|
|
||||||
return events == 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
guard let object = transaction.edit(object) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
try transaction.cancel()
|
|
||||||
}
|
|
||||||
transaction.delete(object)
|
|
||||||
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
XCTAssertTrue(monitor.isObjectDeleted)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: TestObjectObserver
|
|
||||||
|
|
||||||
@available(macOS 10.12, *)
|
|
||||||
class TestObjectObserver: ObjectObserver {
|
|
||||||
|
|
||||||
typealias ObjectEntityType = TestEntity1
|
|
||||||
|
|
||||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "objectMonitor:willUpdateObject:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"object": object
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<String>) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"object": object,
|
|
||||||
"changedPersistentKeys": changedPersistentKeys
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) {
|
|
||||||
|
|
||||||
NotificationCenter.default.post(
|
|
||||||
name: Notification.Name(rawValue: "objectMonitor:didDeleteObject:"),
|
|
||||||
object: self,
|
|
||||||
userInfo: [
|
|
||||||
"object": object
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
//
|
|
||||||
// ObjectPublisherTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - ObjectPublisherTests
|
|
||||||
|
|
||||||
@available(macOS 10.12, *)
|
|
||||||
class ObjectPublisherTests: BaseTestDataTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatObjectPublishers_CanReceiveUpdateNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
guard let object = try stack.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let observer = NSObject()
|
|
||||||
let objectPublisher = stack.publishObject(object)
|
|
||||||
XCTAssertEqual(objectPublisher.object, object)
|
|
||||||
XCTAssertNotNil(objectPublisher.snapshot)
|
|
||||||
|
|
||||||
let didChangeExpectation = self.expectation(description: "didChange")
|
|
||||||
objectPublisher.addObserver(observer) { objectPublisher in
|
|
||||||
|
|
||||||
XCTAssertEqual(objectPublisher.object?.testNumber, NSNumber(value: 10))
|
|
||||||
XCTAssertEqual(objectPublisher.object?.testString, "nil:TestEntity1:10")
|
|
||||||
|
|
||||||
didChangeExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
guard let object = transaction.edit(object) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
try transaction.cancel()
|
|
||||||
}
|
|
||||||
object.testNumber = NSNumber(value: 10)
|
|
||||||
object.testString = "nil:TestEntity1:10"
|
|
||||||
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
|
|
||||||
withExtendedLifetime(objectPublisher, {})
|
|
||||||
withExtendedLifetime(observer, {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatObjectPublishers_CanReceiveDeleteNotifications() {
|
|
||||||
|
|
||||||
self.prepareStack { (stack) in
|
|
||||||
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
|
|
||||||
guard let object = try stack.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let observer = NSObject()
|
|
||||||
let objectPublisher = stack.publishObject(object)
|
|
||||||
XCTAssertEqual(objectPublisher.object, object)
|
|
||||||
XCTAssertNotNil(objectPublisher.snapshot)
|
|
||||||
|
|
||||||
let didChangeExpectation = self.expectation(description: "didChange")
|
|
||||||
objectPublisher.addObserver(observer) { objectPublisher in
|
|
||||||
|
|
||||||
XCTAssertNil(objectPublisher.object)
|
|
||||||
XCTAssertNil(objectPublisher.snapshot)
|
|
||||||
|
|
||||||
didChangeExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveExpectation = self.expectation(description: "save")
|
|
||||||
stack.perform(
|
|
||||||
asynchronous: { (transaction) -> Bool in
|
|
||||||
|
|
||||||
guard let object = transaction.edit(object) else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
try transaction.cancel()
|
|
||||||
}
|
|
||||||
transaction.delete(object)
|
|
||||||
|
|
||||||
return transaction.hasChanges
|
|
||||||
},
|
|
||||||
success: { (hasChanges) in
|
|
||||||
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
},
|
|
||||||
failure: { _ in
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.waitAndCheckExpectations()
|
|
||||||
|
|
||||||
withExtendedLifetime(objectPublisher, {})
|
|
||||||
withExtendedLifetime(observer, {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
//
|
|
||||||
// OrderByTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - OrderByTests
|
|
||||||
|
|
||||||
final class OrderByTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatOrderByClauses_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let orderBy = OrderBy<NSManagedObject>()
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([NSSortDescriptor]()))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key", ascending: false)))
|
|
||||||
XCTAssertTrue(orderBy.sortDescriptors.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
|
|
||||||
let orderBy = OrderBy<NSManagedObject>(sortDescriptor)
|
|
||||||
XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key1", ascending: false)))
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
|
|
||||||
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sortDescriptors = [
|
|
||||||
NSSortDescriptor(key: "key1", ascending: true),
|
|
||||||
NSSortDescriptor(key: "key2", ascending: false)
|
|
||||||
]
|
|
||||||
let orderBy = OrderBy<NSManagedObject>(sortDescriptors)
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
|
||||||
XCTAssertNotEqual(
|
|
||||||
orderBy,
|
|
||||||
OrderBy<NSManagedObject>(
|
|
||||||
[
|
|
||||||
NSSortDescriptor(key: "key1", ascending: false),
|
|
||||||
NSSortDescriptor(key: "key2", ascending: false)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
|
|
||||||
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let orderBy = OrderBy<NSManagedObject>(.ascending("key1"))
|
|
||||||
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptor))
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
|
|
||||||
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let orderBy = OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"))
|
|
||||||
let sortDescriptors = [
|
|
||||||
NSSortDescriptor(key: "key1", ascending: true),
|
|
||||||
NSSortDescriptor(key: "key2", ascending: false)
|
|
||||||
]
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
|
||||||
XCTAssertNotEqual(
|
|
||||||
orderBy,
|
|
||||||
OrderBy<NSManagedObject>(
|
|
||||||
[
|
|
||||||
NSSortDescriptor(key: "key1", ascending: false),
|
|
||||||
NSSortDescriptor(key: "key2", ascending: false)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
|
|
||||||
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sortKeys: [OrderBy<NSManagedObject>.SortKey] = [.ascending("key1"), .descending("key2")]
|
|
||||||
let orderBy = OrderBy<NSManagedObject>(sortKeys)
|
|
||||||
let sortDescriptors = [
|
|
||||||
NSSortDescriptor(key: "key1", ascending: true),
|
|
||||||
NSSortDescriptor(key: "key2", ascending: false)
|
|
||||||
]
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
|
|
||||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
|
||||||
XCTAssertNotEqual(
|
|
||||||
orderBy,
|
|
||||||
OrderBy<NSManagedObject>(
|
|
||||||
[
|
|
||||||
NSSortDescriptor(key: "key1", ascending: false),
|
|
||||||
NSSortDescriptor(key: "key2", ascending: false)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
|
|
||||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
|
|
||||||
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() {
|
|
||||||
|
|
||||||
let orderBy1 = OrderBy<NSManagedObject>(.ascending("key1"))
|
|
||||||
let orderBy2 = OrderBy<NSManagedObject>(.descending("key2"))
|
|
||||||
let orderBy3 = OrderBy<NSManagedObject>(.ascending("key3"))
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let plusOrderBy = orderBy1 + orderBy2 + orderBy3
|
|
||||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
|
|
||||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2"), .ascending("key3")))
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy1 + orderBy2)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy2 + orderBy1)
|
|
||||||
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors + orderBy3.sortDescriptors)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
var plusOrderBy = orderBy1
|
|
||||||
plusOrderBy += orderBy2
|
|
||||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
|
||||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2")))
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1)
|
|
||||||
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors)
|
|
||||||
|
|
||||||
plusOrderBy += orderBy3
|
|
||||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
|
|
||||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")) + OrderBy<NSManagedObject>(.ascending("key3")))
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy1 + orderBy2)
|
|
||||||
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy2 + orderBy1)
|
|
||||||
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors + orderBy3.sortDescriptors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
|
|
||||||
|
|
||||||
let orderBy = OrderBy<NSManagedObject>(.ascending("key"))
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
orderBy.applyToFetchRequest(request)
|
|
||||||
XCTAssertNotNil(request.sortDescriptors)
|
|
||||||
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
//
|
|
||||||
// SectionByTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - SectionByTests
|
|
||||||
|
|
||||||
@available(macOS 10.12, *)
|
|
||||||
final class SectionByTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatSectionByClauses_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sectionBy = SectionBy<NSManagedObject>("key")
|
|
||||||
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
|
|
||||||
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key")
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sectionBy = SectionBy<NSManagedObject>("key") { $0.flatMap { "\($0):suffix" } }
|
|
||||||
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
|
|
||||||
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
|
|
||||||
XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,420 +0,0 @@
|
|||||||
//
|
|
||||||
// SelectTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - SelectTests
|
|
||||||
|
|
||||||
final class SelectTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatAttributeSelectTerms_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term: SelectTerm<NSManagedObject> = "attribute"
|
|
||||||
XCTAssertEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._attribute(let key):
|
|
||||||
XCTAssertEqual(key, "attribute")
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.attribute("attribute")
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._attribute(let key):
|
|
||||||
XCTAssertEqual(key, "attribute")
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatAverageSelectTerms_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.average("attribute")
|
|
||||||
XCTAssertEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "average:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "average(attribute)")
|
|
||||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.average("attribute", as: "alias")
|
|
||||||
XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "average:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "alias")
|
|
||||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatCountSelectTerms_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.count("attribute")
|
|
||||||
XCTAssertEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "count:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "count(attribute)")
|
|
||||||
XCTAssertTrue(nativeType == .integer64AttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.count("attribute", as: "alias")
|
|
||||||
XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "count:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "alias")
|
|
||||||
XCTAssertTrue(nativeType == .integer64AttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatMaximumSelectTerms_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.maximum("attribute")
|
|
||||||
XCTAssertEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "max:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "max(attribute)")
|
|
||||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.maximum("attribute", as: "alias")
|
|
||||||
XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "max:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "alias")
|
|
||||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatMinimumSelectTerms_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.minimum("attribute")
|
|
||||||
XCTAssertEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "min:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "min(attribute)")
|
|
||||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.minimum("attribute", as: "alias")
|
|
||||||
XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "min:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "alias")
|
|
||||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatSumSelectTerms_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.sum("attribute")
|
|
||||||
XCTAssertEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "sum:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "sum(attribute)")
|
|
||||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.sum("attribute", as: "alias")
|
|
||||||
XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
|
||||||
XCTAssertEqual(function, "sum:")
|
|
||||||
XCTAssertEqual(keyPath, "attribute")
|
|
||||||
XCTAssertEqual(alias, "alias")
|
|
||||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatObjectIDSelectTerms_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.objectID()
|
|
||||||
XCTAssertEqual(term, SelectTerm.objectID())
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._identity(let alias, let nativeType):
|
|
||||||
XCTAssertEqual(alias, "objectID")
|
|
||||||
XCTAssertTrue(nativeType == .objectIDAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let term = SelectTerm<NSManagedObject>.objectID(as: "alias")
|
|
||||||
XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
|
||||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
|
||||||
switch term {
|
|
||||||
|
|
||||||
case ._identity(let alias, let nativeType):
|
|
||||||
XCTAssertEqual(alias, "alias")
|
|
||||||
XCTAssertTrue(nativeType == .objectIDAttributeType)
|
|
||||||
|
|
||||||
default:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatSelectClauses_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let term1 = SelectTerm<NSManagedObject>.attribute("attribute1")
|
|
||||||
let term2 = SelectTerm<NSManagedObject>.attribute("attribute2")
|
|
||||||
let term3 = SelectTerm<NSManagedObject>.attribute("attribute3")
|
|
||||||
do {
|
|
||||||
|
|
||||||
let select = Select<NSManagedObject, Int>(term1, term2, term3)
|
|
||||||
XCTAssertEqual(select.selectTerms, [term1, term2, term3])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term2, term3, term1])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term3, term1, term2])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term3, term2, term1])
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let select = Select<NSManagedObject, Int>([term1, term2, term3])
|
|
||||||
XCTAssertEqual(select.selectTerms, [term1, term2, term3])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term2, term3, term1])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term3, term1, term2])
|
|
||||||
XCTAssertNotEqual(select.selectTerms, [term3, term2, term1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,378 +0,0 @@
|
|||||||
//
|
|
||||||
// SetupTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - SetupTests
|
|
||||||
|
|
||||||
class SetupTests: BaseTestDataTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDataStacks_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let schemaHistory = SchemaHistory(
|
|
||||||
XcodeDataModelSchema.from(
|
|
||||||
modelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
let stack = DataStack(schemaHistory: schemaHistory)
|
|
||||||
XCTAssertEqual(stack.coordinator.managedObjectModel, schemaHistory.rawModel)
|
|
||||||
XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator)
|
|
||||||
XCTAssertNil(stack.rootSavingContext.parent)
|
|
||||||
XCTAssertFalse(stack.rootSavingContext.isDataStackContext)
|
|
||||||
XCTAssertFalse(stack.rootSavingContext.isTransactionContext)
|
|
||||||
XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
|
|
||||||
XCTAssertTrue(stack.mainContext.isDataStackContext)
|
|
||||||
XCTAssertFalse(stack.mainContext.isTransactionContext)
|
|
||||||
XCTAssertEqual(stack.schemaHistory.rawModel, schemaHistory.rawModel)
|
|
||||||
XCTAssertTrue(stack.schemaHistory.migrationChain.isValid)
|
|
||||||
XCTAssertTrue(stack.schemaHistory.migrationChain.isEmpty)
|
|
||||||
XCTAssertTrue(stack.schemaHistory.migrationChain.rootVersions.isEmpty)
|
|
||||||
XCTAssertTrue(stack.schemaHistory.migrationChain.leafVersions.isEmpty)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let migrationChain: MigrationChain = ["version1", "version2", "version3", "Model"]
|
|
||||||
|
|
||||||
let stack = self.expectLogger([.logWarning]) {
|
|
||||||
|
|
||||||
DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self),
|
|
||||||
migrationChain: migrationChain
|
|
||||||
)
|
|
||||||
}
|
|
||||||
XCTAssertEqual(stack.modelVersion, "Model")
|
|
||||||
XCTAssertEqual(stack.schemaHistory.migrationChain, migrationChain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatInMemoryStores_SetupCorrectly() {
|
|
||||||
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
let inMemoryStore = InMemoryStore()
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(inMemoryStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(inMemoryStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let inMemoryStore = InMemoryStore(
|
|
||||||
configuration: "Config1"
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(inMemoryStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(inMemoryStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let inMemoryStore = InMemoryStore(
|
|
||||||
configuration: "Config2"
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(inMemoryStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(inMemoryStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatSQLiteStores_SetupCorrectly() {
|
|
||||||
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sqliteStore = SQLiteStore()
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(sqliteStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sqliteStore = SQLiteStore(
|
|
||||||
fileName: "ConfigStore1.sqlite",
|
|
||||||
configuration: "Config1",
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(sqliteStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sqliteStore = SQLiteStore(
|
|
||||||
fileName: "ConfigStore2.sqlite",
|
|
||||||
configuration: "Config2",
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(sqliteStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatSQLiteStores_DeleteFilesCorrectly() {
|
|
||||||
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let sqliteStore = SQLiteStore()
|
|
||||||
func createStore() throws -> [String: Any] {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
try! stack.addStorageAndWait(sqliteStore)
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
}
|
|
||||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
|
||||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
|
||||||
|
|
||||||
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
|
|
||||||
ofType: type(of: sqliteStore).storeType,
|
|
||||||
at: sqliteStore.fileURL,
|
|
||||||
options: sqliteStore.storeOptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let metadata = try createStore()
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
try sqliteStore.cs_eraseStorageAndWait(
|
|
||||||
metadata: metadata,
|
|
||||||
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
|
|
||||||
)
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let metadata = try createStore()
|
|
||||||
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() {
|
|
||||||
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sqliteStore = SQLiteStore.legacy()
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(sqliteStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sqliteStore = SQLiteStore.legacy(
|
|
||||||
fileName: "ConfigStore1.sqlite",
|
|
||||||
configuration: "Config1",
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(sqliteStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let sqliteStore = SQLiteStore.legacy(
|
|
||||||
fileName: "ConfigStore2.sqlite",
|
|
||||||
configuration: "Config2",
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
do {
|
|
||||||
|
|
||||||
try stack.addStorageAndWait(sqliteStore)
|
|
||||||
}
|
|
||||||
catch let error as NSError {
|
|
||||||
|
|
||||||
XCTFail(error.description)
|
|
||||||
}
|
|
||||||
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
|
|
||||||
XCTAssertNotNil(persistentStore)
|
|
||||||
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatLegacySQLiteStores_DeleteFilesCorrectly() {
|
|
||||||
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let sqliteStore = SQLiteStore.legacy()
|
|
||||||
func createStore() throws -> [String: Any] {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
try! stack.addStorageAndWait(
|
|
||||||
SQLiteStore.legacy(
|
|
||||||
fileName: sqliteStore.fileURL.lastPathComponent,
|
|
||||||
configuration: sqliteStore.configuration,
|
|
||||||
migrationMappingProviders: sqliteStore.migrationMappingProviders,
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.prepareTestDataForStack(stack)
|
|
||||||
}
|
|
||||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
|
||||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
|
||||||
|
|
||||||
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
|
|
||||||
ofType: type(of: sqliteStore).storeType,
|
|
||||||
at: sqliteStore.fileURL,
|
|
||||||
options: sqliteStore.storeOptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let metadata = try createStore()
|
|
||||||
let stack = DataStack(
|
|
||||||
xcodeModelName: "Model",
|
|
||||||
bundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
try sqliteStore.cs_eraseStorageAndWait(
|
|
||||||
metadata: metadata,
|
|
||||||
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
|
|
||||||
)
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let metadata = try createStore()
|
|
||||||
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
|
||||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,270 +0,0 @@
|
|||||||
//
|
|
||||||
// StorageInterfaceTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - StorageInterfaceTests
|
|
||||||
|
|
||||||
final class StorageInterfaceTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDefaultInMemoryStores_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let store = InMemoryStore()
|
|
||||||
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
|
|
||||||
XCTAssertNil(store.configuration)
|
|
||||||
XCTAssertNil(store.storeOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatCustomInMemoryStores_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let store = InMemoryStore(configuration: "config1")
|
|
||||||
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
|
|
||||||
XCTAssertEqual(store.configuration, "config1")
|
|
||||||
XCTAssertNil(store.storeOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatSQLiteStoreDefaultDirectories_AreCorrect() {
|
|
||||||
|
|
||||||
#if os(tvOS)
|
|
||||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
|
|
||||||
#else
|
|
||||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
|
|
||||||
#endif
|
|
||||||
|
|
||||||
let defaultSystemDirectory = FileManager.default
|
|
||||||
.urls(for: systemDirectorySearchPath, in: .userDomainMask).first!
|
|
||||||
|
|
||||||
let defaultRootDirectory = defaultSystemDirectory.appendingPathComponent(
|
|
||||||
Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
|
|
||||||
isDirectory: true
|
|
||||||
)
|
|
||||||
let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
|
|
||||||
|
|
||||||
let defaultFileURL = defaultRootDirectory
|
|
||||||
.appendingPathComponent(applicationName, isDirectory: false)
|
|
||||||
.appendingPathExtension("sqlite")
|
|
||||||
|
|
||||||
XCTAssertEqual(SQLiteStore.defaultRootDirectory, defaultRootDirectory)
|
|
||||||
XCTAssertEqual(SQLiteStore.defaultFileURL, defaultFileURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDefaultSQLiteStores_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let store = SQLiteStore()
|
|
||||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
|
||||||
XCTAssertNil(store.configuration)
|
|
||||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
|
||||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL)
|
|
||||||
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
|
|
||||||
XCTAssertEqual(store.localStorageOptions, .none)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let fileURL = FileManager.default.temporaryDirectory
|
|
||||||
.appendingPathComponent(UUID().uuidString, isDirectory: false)
|
|
||||||
.appendingPathExtension("db")
|
|
||||||
let mappingProvider = XcodeSchemaMappingProvider(
|
|
||||||
from: "V1", to: "V2",
|
|
||||||
mappingModelBundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
|
|
||||||
let store = SQLiteStore(
|
|
||||||
fileURL: fileURL,
|
|
||||||
configuration: "config1",
|
|
||||||
migrationMappingProviders: [mappingProvider],
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
|
||||||
XCTAssertEqual(store.configuration, "config1")
|
|
||||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
|
||||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(store.fileURL, fileURL)
|
|
||||||
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
|
|
||||||
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFileNameSQLiteStores_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let fileName = UUID().uuidString + ".db"
|
|
||||||
let mappingProvider = XcodeSchemaMappingProvider(
|
|
||||||
from: "V1", to: "V2",
|
|
||||||
mappingModelBundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
let store = SQLiteStore(
|
|
||||||
fileName: fileName,
|
|
||||||
configuration: "config1",
|
|
||||||
migrationMappingProviders: [mappingProvider],
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
|
||||||
XCTAssertEqual(store.configuration, "config1")
|
|
||||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
|
||||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.defaultRootDirectory)
|
|
||||||
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
|
|
||||||
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
|
|
||||||
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatLegacySQLiteStoreDefaultDirectories_AreCorrect() {
|
|
||||||
|
|
||||||
#if os(tvOS)
|
|
||||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
|
|
||||||
#else
|
|
||||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
|
|
||||||
#endif
|
|
||||||
|
|
||||||
let legacyDefaultRootDirectory = FileManager.default.urls(
|
|
||||||
for: systemDirectorySearchPath,
|
|
||||||
in: .userDomainMask).first!
|
|
||||||
|
|
||||||
let legacyDefaultFileURL = legacyDefaultRootDirectory
|
|
||||||
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
|
|
||||||
.appendingPathExtension("sqlite")
|
|
||||||
|
|
||||||
XCTAssertEqual(SQLiteStore.legacyDefaultRootDirectory, legacyDefaultRootDirectory)
|
|
||||||
XCTAssertEqual(SQLiteStore.legacyDefaultFileURL, legacyDefaultFileURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDefaultLegacySQLiteStores_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let store = SQLiteStore.legacy()
|
|
||||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
|
||||||
XCTAssertNil(store.configuration)
|
|
||||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
|
||||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(store.fileURL, SQLiteStore.legacyDefaultFileURL)
|
|
||||||
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
|
|
||||||
XCTAssertEqual(store.localStorageOptions, .none)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatFileNameLegacySQLiteStores_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
let fileName = UUID().uuidString + ".db"
|
|
||||||
let mappingProvider = XcodeSchemaMappingProvider(
|
|
||||||
from: "V1", to: "V2",
|
|
||||||
mappingModelBundle: Bundle(for: Self.self)
|
|
||||||
)
|
|
||||||
let store = SQLiteStore.legacy(
|
|
||||||
fileName: fileName,
|
|
||||||
configuration: "config1",
|
|
||||||
migrationMappingProviders: [mappingProvider],
|
|
||||||
localStorageOptions: .recreateStoreOnModelMismatch
|
|
||||||
)
|
|
||||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
|
||||||
XCTAssertEqual(store.configuration, "config1")
|
|
||||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
|
||||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
|
||||||
store.storeOptions as NSDictionary?,
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.legacyDefaultRootDirectory)
|
|
||||||
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
|
|
||||||
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
|
|
||||||
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// TestEntity1.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import CoreData
|
|
||||||
|
|
||||||
class TestEntity1: NSManagedObject {
|
|
||||||
|
|
||||||
@NSManaged var testEntityID: NSNumber?
|
|
||||||
@NSManaged var testString: String?
|
|
||||||
@NSManaged var testNumber: NSNumber?
|
|
||||||
@NSManaged var testDate: Date?
|
|
||||||
@NSManaged var testBoolean: NSNumber?
|
|
||||||
@NSManaged var testDecimal: NSDecimalNumber?
|
|
||||||
@NSManaged var testData: Data?
|
|
||||||
@NSManaged var testNil: String?
|
|
||||||
@NSManaged var testToOne: TestEntity1?
|
|
||||||
@NSManaged var testToManyUnordered: NSSet?
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// TestEntity1.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import CoreData
|
|
||||||
|
|
||||||
class TestEntity2: NSManagedObject {
|
|
||||||
|
|
||||||
@NSManaged var testEntityID: NSNumber?
|
|
||||||
@NSManaged var testString: String?
|
|
||||||
@NSManaged var testNumber: NSNumber?
|
|
||||||
@NSManaged var testDate: Date?
|
|
||||||
@NSManaged var testBoolean: NSNumber?
|
|
||||||
@NSManaged var testDecimal: NSDecimalNumber?
|
|
||||||
@NSManaged var testData: Data?
|
|
||||||
@NSManaged var testNil: String?
|
|
||||||
@NSManaged var testToOne: TestEntity2?
|
|
||||||
@NSManaged var testToManyOrdered: NSOrderedSet?
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
//
|
|
||||||
// TweakTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - TweakTests
|
|
||||||
|
|
||||||
final class TweakTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatTweakClauses_ApplyToFetchRequestsCorrectly() {
|
|
||||||
|
|
||||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
|
||||||
let tweak = Tweak {
|
|
||||||
|
|
||||||
$0.fetchOffset = 100
|
|
||||||
$0.fetchLimit = 200
|
|
||||||
$0.predicate = predicate
|
|
||||||
}
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
tweak.applyToFetchRequest(request)
|
|
||||||
XCTAssertEqual(request.fetchOffset, 100)
|
|
||||||
XCTAssertEqual(request.fetchLimit, 200)
|
|
||||||
XCTAssertNotNil(request.predicate)
|
|
||||||
XCTAssertEqual(request.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
//
|
|
||||||
// VersionLockTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - VersionLockTests
|
|
||||||
|
|
||||||
final class VersionLockTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatVersionLocksProduceCorrectHashes() {
|
|
||||||
|
|
||||||
let versionLock: VersionLock = [
|
|
||||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
|
||||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
|
||||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
|
||||||
]
|
|
||||||
XCTAssertEqual(
|
|
||||||
versionLock.description,
|
|
||||||
"""
|
|
||||||
[
|
|
||||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
|
||||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
|
||||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,609 +0,0 @@
|
|||||||
//
|
|
||||||
// WhereTests.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2018 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - XCTAssertAllEqual
|
|
||||||
|
|
||||||
private func XCTAssertAllEqual<O>(_ whereClauses: Where<O>...) {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(whereClauses)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func XCTAssertAllEqual<O>(_ whereClauses: [Where<O>]) {
|
|
||||||
|
|
||||||
for i in whereClauses.indices {
|
|
||||||
|
|
||||||
for j in whereClauses.indices where j != i {
|
|
||||||
|
|
||||||
XCTAssertEqual(whereClauses[i], whereClauses[j])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func XCTAssertAllEqual<D: Equatable>(_ items: D...) {
|
|
||||||
|
|
||||||
for i in items.indices {
|
|
||||||
|
|
||||||
for j in items.indices where j != i {
|
|
||||||
|
|
||||||
XCTAssertEqual(items[i], items[j])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - WhereTests
|
|
||||||
|
|
||||||
final class WhereTests: XCTestCase {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
|
|
||||||
XCTAssertAllEqual(String(keyPath: \Animal.$color), "color")
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatExpressions_HaveCorrectKeyPaths() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
// let keyPathBuilder = TestEntity1.keyPathBuilder()
|
|
||||||
|
|
||||||
// let kp = \TestEntity1.testToOne
|
|
||||||
// print(keyPathBuilder.testString)
|
|
||||||
// print(keyPathBuilder.testToOne)
|
|
||||||
// print(keyPathBuilder.testToOne.testEntityID)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
#keyPath(TestEntity1.testToOne.testEntityID),
|
|
||||||
(\TestEntity1.testToOne ~ \.testEntityID).description,
|
|
||||||
String(keyPath: \TestEntity1.testToOne ~ \.testEntityID)
|
|
||||||
// keyPathBuilder.testToOne.testEntityID.keyPathString
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
#keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered),
|
|
||||||
(\TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered).description,
|
|
||||||
String(keyPath: \TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered)
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
|
||||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).description,
|
|
||||||
String(keyPath: \TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"master.pets",
|
|
||||||
(\Animal.$master ~ \.$pets).description,
|
|
||||||
String(keyPath: \Animal.$master ~ \.$pets)
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"master.pets.species",
|
|
||||||
(\Animal.$master ~ \.$pets ~ \.$species).description,
|
|
||||||
String(keyPath: \Animal.$master ~ \.$pets ~ \.$species)
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"master.pets.master",
|
|
||||||
(\Animal.$master ~ \.$pets ~ \.$master).description,
|
|
||||||
String(keyPath: \Animal.$master ~ \.$pets ~ \.$master)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
#keyPath(TestEntity1.testToOne.testToManyUnordered) + ".@count",
|
|
||||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).count().description,
|
|
||||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).count())
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered) + ".@count",
|
|
||||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count().description,
|
|
||||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"master.pets.@count",
|
|
||||||
(\Animal.$master ~ \.$pets).count().description,
|
|
||||||
String(keyPath: (\Animal.$master ~ \.$pets).count())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ANY " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
|
||||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).any().description,
|
|
||||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).any())
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ANY " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
|
||||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any().description,
|
|
||||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ANY master.pets",
|
|
||||||
(\Animal.$master ~ \.$pets).any().description,
|
|
||||||
String(keyPath: (\Animal.$master ~ \.$pets).any())
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ANY master.pets.species",
|
|
||||||
(\Animal.$master ~ \.$pets ~ \.$species).any().description,
|
|
||||||
String(keyPath: (\Animal.$master ~ \.$pets ~ \.$species).any())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ALL " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
|
||||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).all().description,
|
|
||||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).all())
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ALL " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
|
||||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all().description,
|
|
||||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ALL master.pets",
|
|
||||||
(\Animal.$master ~ \.$pets).all().description,
|
|
||||||
String(keyPath: (\Animal.$master ~ \.$pets).all())
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"ALL master.pets.species",
|
|
||||||
(\Animal.$master ~ \.$pets ~ \.$species).all().description,
|
|
||||||
String(keyPath: (\Animal.$master ~ \.$pets ~ \.$species).all())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"NONE " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
|
||||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).none().description,
|
|
||||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).none())
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"NONE " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
|
||||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none().description,
|
|
||||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"NONE master.pets",
|
|
||||||
(\Animal.$master ~ \.$pets).none().description,
|
|
||||||
String(keyPath: (\Animal.$master ~ \.$pets).none())
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
"NONE master.pets.species",
|
|
||||||
(\Animal.$master ~ \.$pets ~ \.$species).none().description,
|
|
||||||
String(keyPath: (\Animal.$master ~ \.$pets ~ \.$species).none())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatWhereClauses_CanBeCreatedFromExpressionsCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let dummy = "dummy"
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testString) == dummy
|
|
||||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testString)) == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.$master ~ \.$name) == dummy
|
|
||||||
let predicate = NSPredicate(format: "master.name == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let dummy = "dummy"
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToOne ~ \.testString) == dummy
|
|
||||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToOne.testString)) == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.$master ~ \.$spouse ~ \.$name) == dummy
|
|
||||||
let predicate = NSPredicate(format: "master.spouse.name == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let count = 3
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered).count() == count
|
|
||||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToManyUnordered)).@count == %d", count)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.$master ~ \.$pets).count() == count
|
|
||||||
let predicate = NSPredicate(format: "master.pets.@count == %d", count)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let dummy = "dummy"
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).any() == dummy
|
|
||||||
let predicate = NSPredicate(format: "ANY \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.$master ~ \.$pets ~ \.$species).any() == dummy
|
|
||||||
let predicate = NSPredicate(format: "ANY master.pets.species == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let dummy = "dummy"
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).all() == dummy
|
|
||||||
let predicate = NSPredicate(format: "ALL \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.$master ~ \.$pets ~ \.$species).all() == dummy
|
|
||||||
let predicate = NSPredicate(format: "ALL master.pets.species == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let dummy = "dummy"
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).none() == dummy
|
|
||||||
let predicate = NSPredicate(format: "NONE \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.$master ~ \.$pets ~ \.$species).none() == dummy
|
|
||||||
let predicate = NSPredicate(format: "NONE master.pets.species == %@", dummy)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatWhereClauses_ConfigureCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause = Where<NSManagedObject>()
|
|
||||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(true))
|
|
||||||
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, NSPredicate(value: true))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause = Where<NSManagedObject>(true)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>())
|
|
||||||
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, NSPredicate(value: true))
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
|
||||||
let whereClause = Where<NSManagedObject>(predicate)
|
|
||||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause = Where<NSManagedObject>("%K == %@", "key", "value")
|
|
||||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
|
||||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause = Where<NSManagedObject>("%K == %@", argumentArray: ["key", "value"])
|
|
||||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
|
||||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
|
|
||||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
|
||||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let whereClause = Where<NSManagedObject>("key", isMemberOf: ["value1", "value2", "value3"])
|
|
||||||
let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"])
|
|
||||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatWhereClauses_BridgeArgumentsCorrectly() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value: Int = 100
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value = NSNumber(value: 100)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value.intValue),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value.intValue),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value.intValue)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value: Int64 = Int64.max
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value = NSNumber(value: Int64.max)
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %d", "key", value.int64Value),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value.int64Value),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value.int64Value)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value: String = "value"
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K == %s", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %s", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %s", "key", NSString(string: value)),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", NSString(string: value)),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value as NSString),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: NSString(string: value))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value = NSString(string: "value")
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K == %s", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %s", "key", value as String),
|
|
||||||
Where<NSManagedObject>("%K == %s", "key", value as String as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value as String),
|
|
||||||
Where<NSManagedObject>("%K == %@", "key", value as String as AnyObject),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value as String),
|
|
||||||
Where<NSManagedObject>("key", isEqualTo: value as String as NSString)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value: [Int] = [100, 200]
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
|
|
||||||
Where<NSManagedObject>("key", isMemberOf: value)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let value: [Int64] = [Int64.min, 100, Int64.max]
|
|
||||||
XCTAssertAllEqual(
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
|
|
||||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
|
|
||||||
Where<NSManagedObject>("key", isMemberOf: value)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() {
|
|
||||||
|
|
||||||
let whereClause1 = Where<NSManagedObject>("key1", isEqualTo: "value1")
|
|
||||||
let whereClause2 = Where<NSManagedObject>("key2", isEqualTo: "value2")
|
|
||||||
let whereClause3 = Where<NSManagedObject>("key3", isEqualTo: "value3")
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let notWhere = !whereClause1
|
|
||||||
let notPredicate = NSCompoundPredicate(
|
|
||||||
type: .not,
|
|
||||||
subpredicates: [whereClause1.predicate]
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(notWhere.predicate, notPredicate)
|
|
||||||
XCTAssertAllEqual(notWhere, !whereClause1)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let andWhere = whereClause1 && whereClause2 && whereClause3
|
|
||||||
let andPredicate = NSCompoundPredicate(
|
|
||||||
type: .and,
|
|
||||||
subpredicates: [
|
|
||||||
NSCompoundPredicate(
|
|
||||||
type: .and,
|
|
||||||
subpredicates: [whereClause1.predicate, whereClause2.predicate]
|
|
||||||
),
|
|
||||||
whereClause3.predicate
|
|
||||||
]
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(andWhere.predicate, andPredicate)
|
|
||||||
XCTAssertAllEqual(andWhere, whereClause1 && whereClause2 && whereClause3)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let andWhere = whereClause1 && whereClause2 && whereClause3
|
|
||||||
let noneWhere: Where<NSManagedObject>? = nil
|
|
||||||
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
|
|
||||||
|
|
||||||
|
|
||||||
let finalNoneWhere = andWhere &&? noneWhere
|
|
||||||
let finalSomeWhere = andWhere &&? someWhere
|
|
||||||
let unwrappedFinalSomeWhere = andWhere && someWhere!
|
|
||||||
|
|
||||||
|
|
||||||
XCTAssertAllEqual(andWhere.predicate, finalNoneWhere.predicate)
|
|
||||||
XCTAssertAllEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let orWhere = whereClause1 || whereClause2 || whereClause3
|
|
||||||
let orPredicate = NSCompoundPredicate(
|
|
||||||
type: .or,
|
|
||||||
subpredicates: [
|
|
||||||
NSCompoundPredicate(
|
|
||||||
type: .or,
|
|
||||||
subpredicates: [whereClause1.predicate, whereClause2.predicate]
|
|
||||||
),
|
|
||||||
whereClause3.predicate
|
|
||||||
]
|
|
||||||
)
|
|
||||||
XCTAssertAllEqual(orWhere.predicate, orPredicate)
|
|
||||||
XCTAssertAllEqual(orWhere, whereClause1 || whereClause2 || whereClause3)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
|
|
||||||
let orWhere = whereClause1 || whereClause2 || whereClause3
|
|
||||||
let noneWhere: Where<NSManagedObject>? = nil
|
|
||||||
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
|
|
||||||
|
|
||||||
|
|
||||||
let finalNoneWhere = orWhere &&? noneWhere
|
|
||||||
let finalSomeWhere = orWhere &&? someWhere
|
|
||||||
let unwrappedFinalSomeWhere = orWhere && someWhere!
|
|
||||||
|
|
||||||
XCTAssertAllEqual(orWhere.predicate, finalNoneWhere.predicate)
|
|
||||||
XCTAssertAllEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
|
|
||||||
|
|
||||||
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
|
|
||||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
|
||||||
whereClause.applyToFetchRequest(request)
|
|
||||||
XCTAssertNotNil(request.predicate)
|
|
||||||
XCTAssertAllEqual(request.predicate, whereClause.predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,973 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 50;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
B531EFE724EA762D005F247D /* Menu.PlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B531EFE624EA762D005F247D /* Menu.PlaceholderView.swift */; };
|
|
||||||
B531EFE924EB5A53005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = B531EFE824EB5A52005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift */; };
|
|
||||||
B531EFEB24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = B531EFEA24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift */; };
|
|
||||||
B531EFED24EB7453005F247D /* Modern.PokedexDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B531EFEC24EB7453005F247D /* Modern.PokedexDemo.MainView.swift */; };
|
|
||||||
B54D2F7A25119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F7925119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel */; };
|
|
||||||
B54D2F7C251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F7B251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift */; };
|
|
||||||
B54D2F7E25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F7D25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel */; };
|
|
||||||
B54D2F852511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F842511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift */; };
|
|
||||||
B566C8E824F9D406001134A1 /* Modern.PokedexDemo.ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8E724F9D406001134A1 /* Modern.PokedexDemo.ListView.swift */; };
|
|
||||||
B566C8EA24F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8E924F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift */; };
|
|
||||||
B566C8EC24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8EB24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift */; };
|
|
||||||
B566C8EE24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8ED24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift */; };
|
|
||||||
B5931B4225124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4125124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift */; };
|
|
||||||
B5931B442512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B432512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift */; };
|
|
||||||
B5931B46251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B45251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift */; };
|
|
||||||
B5931B4825124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4725124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift */; };
|
|
||||||
B5931B4A25124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4925124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift */; };
|
|
||||||
B5931B4C251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4B251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift */; };
|
|
||||||
B5A3911D24E5429200E7E8BD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3911C24E5429200E7E8BD /* AppDelegate.swift */; };
|
|
||||||
B5A3911F24E5429200E7E8BD /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3911E24E5429200E7E8BD /* SceneDelegate.swift */; };
|
|
||||||
B5A3912124E5429200E7E8BD /* Menu.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3912024E5429200E7E8BD /* Menu.MainView.swift */; };
|
|
||||||
B5A3912324E5429300E7E8BD /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B5A3912224E5429300E7E8BD /* Images.xcassets */; };
|
|
||||||
B5A3912624E5429300E7E8BD /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B5A3912524E5429300E7E8BD /* Preview Assets.xcassets */; };
|
|
||||||
B5A3912924E5429300E7E8BD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5A3912724E5429300E7E8BD /* LaunchScreen.storyboard */; };
|
|
||||||
B5A3913424E6170500E7E8BD /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3913324E6170500E7E8BD /* Menu.swift */; };
|
|
||||||
B5A3915324E6537F00E7E8BD /* Menu.ItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915224E6537F00E7E8BD /* Menu.ItemView.swift */; };
|
|
||||||
B5A3915924E685EC00E7E8BD /* Classic.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915824E685EC00E7E8BD /* Classic.swift */; };
|
|
||||||
B5A3915B24E685FE00E7E8BD /* Modern.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915A24E685FE00E7E8BD /* Modern.swift */; };
|
|
||||||
B5A3915E24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915D24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift */; };
|
|
||||||
B5A3916024E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915F24E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift */; };
|
|
||||||
B5A3916224E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3916124E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift */; };
|
|
||||||
B5A3916524E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3916424E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift */; };
|
|
||||||
B5A3916B24E698F900E7E8BD /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916724E698F900E7E8BD /* CoreStore.framework */; };
|
|
||||||
B5A3916C24E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916724E698F900E7E8BD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
|
||||||
B5A3916D24E698F900E7E8BD /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916824E698F900E7E8BD /* CoreStore.framework */; };
|
|
||||||
B5A3916E24E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916824E698F900E7E8BD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
|
||||||
B5A3916F24E698F900E7E8BD /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916924E698F900E7E8BD /* CoreStore.framework */; };
|
|
||||||
B5A3917024E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916924E698F900E7E8BD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
|
||||||
B5A3917124E698F900E7E8BD /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916A24E698F900E7E8BD /* CoreStore.framework */; };
|
|
||||||
B5A3917224E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3916A24E698F900E7E8BD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
|
||||||
B5A3917524E6990200E7E8BD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3917424E6990200E7E8BD /* MapKit.framework */; };
|
|
||||||
B5A3917724E6990700E7E8BD /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3917624E6990700E7E8BD /* CoreLocation.framework */; };
|
|
||||||
B5A3917924E6991600E7E8BD /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A3917824E6991600E7E8BD /* SwiftUI.framework */; };
|
|
||||||
B5A3917C24E6A76C00E7E8BD /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3917B24E6A76C00E7E8BD /* LazyView.swift */; };
|
|
||||||
B5A3917E24E7728400E7E8BD /* Modern.PlacemarksDemo.Geocoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3917D24E7728400E7E8BD /* Modern.PlacemarksDemo.Geocoder.swift */; };
|
|
||||||
B5A3918024E787D900E7E8BD /* InstructionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3917F24E787D900E7E8BD /* InstructionsView.swift */; };
|
|
||||||
B5A3918324E7A21800E7E8BD /* Modern.TimeZonesDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3918224E7A21800E7E8BD /* Modern.TimeZonesDemo.swift */; };
|
|
||||||
B5A3918624E7A54A00E7E8BD /* Modern.TimeZonesDemo.TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3918524E7A54A00E7E8BD /* Modern.TimeZonesDemo.TimeZone.swift */; };
|
|
||||||
B5A3918824E7A8F900E7E8BD /* ⭐️Modern.TimeZonesDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3918724E7A8F900E7E8BD /* ⭐️Modern.TimeZonesDemo.MainView.swift */; };
|
|
||||||
B5A3918A24E7AD1800E7E8BD /* Modern.TimeZonesDemo.ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3918924E7AD1800E7E8BD /* Modern.TimeZonesDemo.ListView.swift */; };
|
|
||||||
B5A3918C24E7B44B00E7E8BD /* Modern.TimeZonesDemo.ItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3918B24E7B44B00E7E8BD /* Modern.TimeZonesDemo.ItemView.swift */; };
|
|
||||||
B5A3918F24E7E06500E7E8BD /* Modern.ColorsDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3918E24E7E06500E7E8BD /* Modern.ColorsDemo.swift */; };
|
|
||||||
B5A3919224E7E0C600E7E8BD /* Modern.ColorsDemo.Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3919124E7E0C600E7E8BD /* Modern.ColorsDemo.Palette.swift */; };
|
|
||||||
B5A3919424E7E36700E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3919324E7E36700E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ListView.swift */; };
|
|
||||||
B5A3919624E7E4AC00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3919524E7E4AC00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift */; };
|
|
||||||
B5A3919824E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3919724E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift */; };
|
|
||||||
B5A3919A24E8207A00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3919924E8207A00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift */; };
|
|
||||||
B5A3919E24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3919D24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift */; };
|
|
||||||
B5A391A024E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3919F24E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift */; };
|
|
||||||
B5A391A224E8F01F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391A124E8F01F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.ListViewController.swift */; };
|
|
||||||
B5A391A424E8F04300E7E8BD /* Modern.ColorsDemo.UIKit.ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391A324E8F04300E7E8BD /* Modern.ColorsDemo.UIKit.ListView.swift */; };
|
|
||||||
B5A391A624E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391A524E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift */; };
|
|
||||||
B5A391AA24E9104300E7E8BD /* Modern.ColorsDemo.UIKit.ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391A924E9104300E7E8BD /* Modern.ColorsDemo.UIKit.ItemCell.swift */; };
|
|
||||||
B5A391AC24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391AB24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift */; };
|
|
||||||
B5A391AE24E9150F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391AD24E9150F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift */; };
|
|
||||||
B5A391B124E96AF600E7E8BD /* Modern.PokedexDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391B024E96AF600E7E8BD /* Modern.PokedexDemo.swift */; };
|
|
||||||
B5A391B424E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391B324E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift */; };
|
|
||||||
B5A391B924E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391B824E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift */; };
|
|
||||||
B5A391BB24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391BA24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift */; };
|
|
||||||
B5A543D724FB7478000DC5E3 /* Classic.ColorsDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543D624FB7478000DC5E3 /* Classic.ColorsDemo.swift */; };
|
|
||||||
B5A543DB24FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5A543D924FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld */; };
|
|
||||||
B5A543DD24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543DC24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift */; };
|
|
||||||
B5A543E724FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543E624FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift */; };
|
|
||||||
B5A543E924FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543E824FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift */; };
|
|
||||||
B5A543EB24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543EA24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift */; };
|
|
||||||
B5A543ED24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543EC24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift */; };
|
|
||||||
B5A543EF24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543EE24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift */; };
|
|
||||||
B5A543F124FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543F024FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift */; };
|
|
||||||
B5A543F324FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543F224FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift */; };
|
|
||||||
B5A543F624FBF13A000DC5E3 /* Advanced.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543F524FBF13A000DC5E3 /* Advanced.swift */; };
|
|
||||||
B5A543FB2504840E000DC5E3 /* Advanced.EvolutionDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543FA2504840E000DC5E3 /* Advanced.EvolutionDemo.swift */; };
|
|
||||||
B5A543FF250487B1000DC5E3 /* Advanced.EvolutionDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543FE250487B1000DC5E3 /* Advanced.EvolutionDemo.MainView.swift */; };
|
|
||||||
B5A54401250487C7000DC5E3 /* Advanced.EvolutionDemo.ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A54400250487C7000DC5E3 /* Advanced.EvolutionDemo.ListView.swift */; };
|
|
||||||
B5A54403250487D5000DC5E3 /* Advanced.EvolutionDemo.ItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A54402250487D4000DC5E3 /* Advanced.EvolutionDemo.ItemView.swift */; };
|
|
||||||
B5A54405250487F5000DC5E3 /* Advanced.EvolutionDemo.CreatureType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A54404250487F5000DC5E3 /* Advanced.EvolutionDemo.CreatureType.swift */; };
|
|
||||||
B5A5440725049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5440625049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift */; };
|
|
||||||
B5A5440925049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5440825049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift */; };
|
|
||||||
B5A5440B25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5440A25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift */; };
|
|
||||||
B5A5440D2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5440C2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift */; };
|
|
||||||
B5C18F3325138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C18F3225138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift */; };
|
|
||||||
B5D6F1F8250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F1F7250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift */; };
|
|
||||||
B5D6F1FC250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F1FB250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift */; };
|
|
||||||
B5D6F1FE250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F1FD250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift */; };
|
|
||||||
B5D6F205250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F204250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift */; };
|
|
||||||
B5D6F207250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F206250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift */; };
|
|
||||||
B5D6F209250E14AA00DF5D2F /* ⭐️Advanced.EvolutionDemo.Migrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F208250E14AA00DF5D2F /* ⭐️Advanced.EvolutionDemo.Migrator.swift */; };
|
|
||||||
B5D6F210250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F20E250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodeld */; };
|
|
||||||
B5E32C9024FA41F9003F46AD /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E32C8F24FA41F9003F46AD /* ImageDownloader.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
B5A3917324E698F900E7E8BD /* Embed Frameworks */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 10;
|
|
||||||
files = (
|
|
||||||
B5A3916C24E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */,
|
|
||||||
B5A3917224E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */,
|
|
||||||
B5A3917024E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */,
|
|
||||||
B5A3916E24E698F900E7E8BD /* CoreStore.framework in Embed Frameworks */,
|
|
||||||
);
|
|
||||||
name = "Embed Frameworks";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
B531EFE624EA762D005F247D /* Menu.PlaceholderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.PlaceholderView.swift; sourceTree = "<group>"; };
|
|
||||||
B531EFE824EB5A52005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.PokedexEntry.swift"; sourceTree = "<group>"; };
|
|
||||||
B531EFEA24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.Service.swift"; sourceTree = "<group>"; };
|
|
||||||
B531EFEC24EB7453005F247D /* Modern.PokedexDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.MainView.swift; sourceTree = "<group>"; };
|
|
||||||
B54D2F7925119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel; sourceTree = "<group>"; };
|
|
||||||
B54D2F7B251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift; sourceTree = "<group>"; };
|
|
||||||
B54D2F7D25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel; sourceTree = "<group>"; };
|
|
||||||
B54D2F842511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.CreaturesDataSource.swift; sourceTree = "<group>"; };
|
|
||||||
B566C8E724F9D406001134A1 /* Modern.PokedexDemo.ListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.ListView.swift; sourceTree = "<group>"; };
|
|
||||||
B566C8E924F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.ListViewController.swift; sourceTree = "<group>"; };
|
|
||||||
B566C8EB24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.ItemCell.swift; sourceTree = "<group>"; };
|
|
||||||
B566C8ED24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.Details.swift; sourceTree = "<group>"; };
|
|
||||||
B5931B4125124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V1.FromV2.swift; sourceTree = "<group>"; };
|
|
||||||
B5931B432512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.FromV1.swift; sourceTree = "<group>"; };
|
|
||||||
B5931B45251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V3.FromV2.swift; sourceTree = "<group>"; };
|
|
||||||
B5931B4725124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V4.FromV3.swift; sourceTree = "<group>"; };
|
|
||||||
B5931B4925124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V3.FromV4.swift; sourceTree = "<group>"; };
|
|
||||||
B5931B4B251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.FromV3.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3911924E5429200E7E8BD /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
B5A3911C24E5429200E7E8BD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3911E24E5429200E7E8BD /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3912024E5429200E7E8BD /* Menu.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.MainView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3912224E5429300E7E8BD /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
|
||||||
B5A3912524E5429300E7E8BD /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
|
||||||
B5A3912824E5429300E7E8BD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
|
||||||
B5A3913324E6170500E7E8BD /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3913924E62A9A00E7E8BD /* Rakefile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; fileEncoding = 4; path = Rakefile; sourceTree = SOURCE_ROOT; };
|
|
||||||
B5A3914124E62D3900E7E8BD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
B5A3915224E6537F00E7E8BD /* Menu.ItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.ItemView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3915824E685EC00E7E8BD /* Classic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3915A24E685FE00E7E8BD /* Modern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3915D24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PlacemarksDemo.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A3915F24E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PlacemarksDemo.MapView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3916124E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PlacemarksDemo.MainView.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A3916424E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PlacemarksDemo.Place.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3916724E698F900E7E8BD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
B5A3916824E698F900E7E8BD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
B5A3916924E698F900E7E8BD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
B5A3916A24E698F900E7E8BD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
B5A3917424E6990200E7E8BD /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.6.sdk/System/Library/Frameworks/MapKit.framework; sourceTree = DEVELOPER_DIR; };
|
|
||||||
B5A3917624E6990700E7E8BD /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.6.sdk/System/Library/Frameworks/CoreLocation.framework; sourceTree = DEVELOPER_DIR; };
|
|
||||||
B5A3917824E6991600E7E8BD /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.6.sdk/System/Library/Frameworks/SwiftUI.framework; sourceTree = DEVELOPER_DIR; };
|
|
||||||
B5A3917B24E6A76C00E7E8BD /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3917D24E7728400E7E8BD /* Modern.PlacemarksDemo.Geocoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PlacemarksDemo.Geocoder.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3917F24E787D900E7E8BD /* InstructionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionsView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3918224E7A21800E7E8BD /* Modern.TimeZonesDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.TimeZonesDemo.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3918524E7A54A00E7E8BD /* Modern.TimeZonesDemo.TimeZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.TimeZonesDemo.TimeZone.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3918724E7A8F900E7E8BD /* ⭐️Modern.TimeZonesDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.TimeZonesDemo.MainView.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A3918924E7AD1800E7E8BD /* Modern.TimeZonesDemo.ListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.TimeZonesDemo.ListView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3918B24E7B44B00E7E8BD /* Modern.TimeZonesDemo.ItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.TimeZonesDemo.ItemView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3918E24E7E06500E7E8BD /* Modern.ColorsDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3919124E7E0C600E7E8BD /* Modern.ColorsDemo.Palette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.Palette.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3919324E7E36700E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.ColorsDemo.SwiftUI.ListView.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A3919524E7E4AC00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A3919724E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.Filter.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3919924E8207A00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A3919D24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.SwiftUI.swift; sourceTree = "<group>"; };
|
|
||||||
B5A3919F24E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.UIKit.swift; sourceTree = "<group>"; };
|
|
||||||
B5A391A124E8F01F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.ListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.ColorsDemo.UIKit.ListViewController.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A391A324E8F04300E7E8BD /* Modern.ColorsDemo.UIKit.ListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.UIKit.ListView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A391A524E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.ColorsDemo.MainView.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A391A924E9104300E7E8BD /* Modern.ColorsDemo.UIKit.ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.UIKit.ItemCell.swift; sourceTree = "<group>"; };
|
|
||||||
B5A391AB24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.ColorsDemo.UIKit.DetailView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A391AD24E9150F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A391B024E96AF600E7E8BD /* Modern.PokedexDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.swift; sourceTree = "<group>"; };
|
|
||||||
B5A391B324E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.Form.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A391B824E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.Species.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A391BA24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.PokemonType.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A543D624FB7478000DC5E3 /* Classic.ColorsDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543DA24FB7513000DC5E3 /* ColorsDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = ColorsDemo.xcdatamodel; sourceTree = "<group>"; };
|
|
||||||
B5A543DC24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.Palette.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543E624FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.Filter.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543E824FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.DetailView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543EA24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Classic.ColorsDemo.DetailViewController.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A543EC24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.MainView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543EE24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.LIstView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543F024FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Classic.ColorsDemo.ListViewController.swift"; sourceTree = "<group>"; };
|
|
||||||
B5A543F224FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.ItemCell.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543F524FBF13A000DC5E3 /* Advanced.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543FA2504840E000DC5E3 /* Advanced.EvolutionDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.swift; sourceTree = "<group>"; };
|
|
||||||
B5A543FE250487B1000DC5E3 /* Advanced.EvolutionDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.MainView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A54400250487C7000DC5E3 /* Advanced.EvolutionDemo.ListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.ListView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A54402250487D4000DC5E3 /* Advanced.EvolutionDemo.ItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.ItemView.swift; sourceTree = "<group>"; };
|
|
||||||
B5A54404250487F5000DC5E3 /* Advanced.EvolutionDemo.CreatureType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.CreatureType.swift; sourceTree = "<group>"; };
|
|
||||||
B5A5440625049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V1.Creature.swift; sourceTree = "<group>"; };
|
|
||||||
B5A5440825049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.Creature.swift; sourceTree = "<group>"; };
|
|
||||||
B5A5440A25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V3.Creature.swift; sourceTree = "<group>"; };
|
|
||||||
B5A5440C2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V4.Creature.swift; sourceTree = "<group>"; };
|
|
||||||
B5C18F3225138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.ProgressView.swift; sourceTree = "<group>"; };
|
|
||||||
B5D6F1F7250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V1.swift; sourceTree = "<group>"; };
|
|
||||||
B5D6F1FB250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.swift; sourceTree = "<group>"; };
|
|
||||||
B5D6F1FD250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.GeologicalPeriod.swift; sourceTree = "<group>"; };
|
|
||||||
B5D6F204250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V3.swift; sourceTree = "<group>"; };
|
|
||||||
B5D6F206250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V4.swift; sourceTree = "<group>"; };
|
|
||||||
B5D6F208250E14AA00DF5D2F /* ⭐️Advanced.EvolutionDemo.Migrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Advanced.EvolutionDemo.Migrator.swift"; sourceTree = "<group>"; };
|
|
||||||
B5D6F20F250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Advanced.EvolutionDemo.V1.xcdatamodel; sourceTree = "<group>"; };
|
|
||||||
B5D6F211250E1E7000DF5D2F /* Advanced.EvolutionDemo.V2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Advanced.EvolutionDemo.V2.xcdatamodel; sourceTree = "<group>"; };
|
|
||||||
B5E32C8F24FA41F9003F46AD /* ImageDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDownloader.swift; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
B5A3911624E5429200E7E8BD /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
B5A3917724E6990700E7E8BD /* CoreLocation.framework in Frameworks */,
|
|
||||||
B5A3916B24E698F900E7E8BD /* CoreStore.framework in Frameworks */,
|
|
||||||
B5A3917124E698F900E7E8BD /* CoreStore.framework in Frameworks */,
|
|
||||||
B5A3917924E6991600E7E8BD /* SwiftUI.framework in Frameworks */,
|
|
||||||
B5A3917524E6990200E7E8BD /* MapKit.framework in Frameworks */,
|
|
||||||
B5A3916F24E698F900E7E8BD /* CoreStore.framework in Frameworks */,
|
|
||||||
B5A3916D24E698F900E7E8BD /* CoreStore.framework in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
B5A3910E24E5424E00E7E8BD = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3913D24E62C6C00E7E8BD /* Metadata */,
|
|
||||||
B5A3911B24E5429200E7E8BD /* ⭐️Sources */,
|
|
||||||
B5A3913E24E62CB200E7E8BD /* Resources */,
|
|
||||||
B5A3911A24E5429200E7E8BD /* Products */,
|
|
||||||
B5A3916624E698F900E7E8BD /* Frameworks */,
|
|
||||||
);
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3911A24E5429200E7E8BD /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3911924E5429200E7E8BD /* Demo.app */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3911B24E5429200E7E8BD /* ⭐️Sources */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3911C24E5429200E7E8BD /* AppDelegate.swift */,
|
|
||||||
B5A3911E24E5429200E7E8BD /* SceneDelegate.swift */,
|
|
||||||
B5A3915524E6858A00E7E8BD /* ⭐️Demos */,
|
|
||||||
B5A3917A24E6A75F00E7E8BD /* Helpers */,
|
|
||||||
);
|
|
||||||
path = "⭐️Sources";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3912424E5429300E7E8BD /* Preview Content */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3912524E5429300E7E8BD /* Preview Assets.xcassets */,
|
|
||||||
);
|
|
||||||
path = "Preview Content";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3913D24E62C6C00E7E8BD /* Metadata */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3913924E62A9A00E7E8BD /* Rakefile */,
|
|
||||||
B5A3914124E62D3900E7E8BD /* Info.plist */,
|
|
||||||
);
|
|
||||||
name = Metadata;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3913E24E62CB200E7E8BD /* Resources */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3912724E5429300E7E8BD /* LaunchScreen.storyboard */,
|
|
||||||
B5A3912224E5429300E7E8BD /* Images.xcassets */,
|
|
||||||
B5A3912424E5429300E7E8BD /* Preview Content */,
|
|
||||||
);
|
|
||||||
path = Resources;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3915424E6857F00E7E8BD /* Menu */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3913324E6170500E7E8BD /* Menu.swift */,
|
|
||||||
B5A3912024E5429200E7E8BD /* Menu.MainView.swift */,
|
|
||||||
B5A3915224E6537F00E7E8BD /* Menu.ItemView.swift */,
|
|
||||||
B531EFE624EA762D005F247D /* Menu.PlaceholderView.swift */,
|
|
||||||
);
|
|
||||||
path = Menu;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3915524E6858A00E7E8BD /* ⭐️Demos */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3915624E685B700E7E8BD /* ⭐️Modern */,
|
|
||||||
B5A3915724E685D300E7E8BD /* ⭐️Classic */,
|
|
||||||
B5A543F424FBF107000DC5E3 /* ⭐️Advanced */,
|
|
||||||
);
|
|
||||||
path = "⭐️Demos";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3915624E685B700E7E8BD /* ⭐️Modern */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3915A24E685FE00E7E8BD /* Modern.swift */,
|
|
||||||
B5A3915C24E6921E00E7E8BD /* ⭐️PlacemarksDemo */,
|
|
||||||
B5A3918124E7A1EF00E7E8BD /* ⭐️TimeZonesDemo */,
|
|
||||||
B5A3918D24E7DE7A00E7E8BD /* ⭐️ColorsDemo */,
|
|
||||||
B5A391AF24E96AD600E7E8BD /* ⭐️PokedexDemo */,
|
|
||||||
);
|
|
||||||
path = "⭐️Modern";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3915724E685D300E7E8BD /* ⭐️Classic */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3915824E685EC00E7E8BD /* Classic.swift */,
|
|
||||||
B5A543D524FB73B2000DC5E3 /* ⭐️ColorsDemo */,
|
|
||||||
);
|
|
||||||
path = "⭐️Classic";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3915C24E6921E00E7E8BD /* ⭐️PlacemarksDemo */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3915D24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift */,
|
|
||||||
B5A3916124E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift */,
|
|
||||||
B5A3915F24E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift */,
|
|
||||||
B5A3917D24E7728400E7E8BD /* Modern.PlacemarksDemo.Geocoder.swift */,
|
|
||||||
B5A3916324E698B300E7E8BD /* Models */,
|
|
||||||
);
|
|
||||||
path = "⭐️PlacemarksDemo";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3916324E698B300E7E8BD /* Models */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3916424E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift */,
|
|
||||||
);
|
|
||||||
name = Models;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3916624E698F900E7E8BD /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3917824E6991600E7E8BD /* SwiftUI.framework */,
|
|
||||||
B5A3917624E6990700E7E8BD /* CoreLocation.framework */,
|
|
||||||
B5A3917424E6990200E7E8BD /* MapKit.framework */,
|
|
||||||
B5A3916724E698F900E7E8BD /* CoreStore.framework */,
|
|
||||||
B5A3916824E698F900E7E8BD /* CoreStore.framework */,
|
|
||||||
B5A3916924E698F900E7E8BD /* CoreStore.framework */,
|
|
||||||
B5A3916A24E698F900E7E8BD /* CoreStore.framework */,
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3917A24E6A75F00E7E8BD /* Helpers */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3917B24E6A76C00E7E8BD /* LazyView.swift */,
|
|
||||||
B5A3917F24E787D900E7E8BD /* InstructionsView.swift */,
|
|
||||||
B5E32C8F24FA41F9003F46AD /* ImageDownloader.swift */,
|
|
||||||
B5A3915424E6857F00E7E8BD /* Menu */,
|
|
||||||
);
|
|
||||||
path = Helpers;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3918124E7A1EF00E7E8BD /* ⭐️TimeZonesDemo */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3918224E7A21800E7E8BD /* Modern.TimeZonesDemo.swift */,
|
|
||||||
B5A3918724E7A8F900E7E8BD /* ⭐️Modern.TimeZonesDemo.MainView.swift */,
|
|
||||||
B5A3918924E7AD1800E7E8BD /* Modern.TimeZonesDemo.ListView.swift */,
|
|
||||||
B5A3918B24E7B44B00E7E8BD /* Modern.TimeZonesDemo.ItemView.swift */,
|
|
||||||
B5A3918424E7A53300E7E8BD /* Models */,
|
|
||||||
);
|
|
||||||
path = "⭐️TimeZonesDemo";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3918424E7A53300E7E8BD /* Models */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3918524E7A54A00E7E8BD /* Modern.TimeZonesDemo.TimeZone.swift */,
|
|
||||||
);
|
|
||||||
name = Models;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3918D24E7DE7A00E7E8BD /* ⭐️ColorsDemo */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3918E24E7E06500E7E8BD /* Modern.ColorsDemo.swift */,
|
|
||||||
B5A3919724E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift */,
|
|
||||||
B5A391A524E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift */,
|
|
||||||
B5A3919C24E8EE9000E7E8BD /* ⭐️UIKit */,
|
|
||||||
B5A3919B24E8EE8100E7E8BD /* ⭐️SwiftUI */,
|
|
||||||
B5A3919024E7E0B000E7E8BD /* Models */,
|
|
||||||
);
|
|
||||||
path = "⭐️ColorsDemo";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3919024E7E0B000E7E8BD /* Models */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3919124E7E0C600E7E8BD /* Modern.ColorsDemo.Palette.swift */,
|
|
||||||
);
|
|
||||||
name = Models;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3919B24E8EE8100E7E8BD /* ⭐️SwiftUI */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3919D24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift */,
|
|
||||||
B5A3919324E7E36700E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ListView.swift */,
|
|
||||||
B5A3919524E7E4AC00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift */,
|
|
||||||
B5A3919924E8207A00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift */,
|
|
||||||
);
|
|
||||||
name = "⭐️SwiftUI";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A3919C24E8EE9000E7E8BD /* ⭐️UIKit */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A3919F24E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift */,
|
|
||||||
B5A391A324E8F04300E7E8BD /* Modern.ColorsDemo.UIKit.ListView.swift */,
|
|
||||||
B5A391A124E8F01F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.ListViewController.swift */,
|
|
||||||
B5A391A924E9104300E7E8BD /* Modern.ColorsDemo.UIKit.ItemCell.swift */,
|
|
||||||
B5A391AB24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift */,
|
|
||||||
B5A391AD24E9150F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift */,
|
|
||||||
);
|
|
||||||
name = "⭐️UIKit";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A391AF24E96AD600E7E8BD /* ⭐️PokedexDemo */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A391B024E96AF600E7E8BD /* Modern.PokedexDemo.swift */,
|
|
||||||
B531EFEA24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift */,
|
|
||||||
B531EFEC24EB7453005F247D /* Modern.PokedexDemo.MainView.swift */,
|
|
||||||
B566C8E724F9D406001134A1 /* Modern.PokedexDemo.ListView.swift */,
|
|
||||||
B566C8E924F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift */,
|
|
||||||
B566C8EB24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift */,
|
|
||||||
B5A391B224E96B7400E7E8BD /* ⭐️Models */,
|
|
||||||
);
|
|
||||||
path = "⭐️PokedexDemo";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A391B224E96B7400E7E8BD /* ⭐️Models */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B531EFE824EB5A52005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift */,
|
|
||||||
B566C8ED24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift */,
|
|
||||||
B5A391B824E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift */,
|
|
||||||
B5A391B324E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift */,
|
|
||||||
B5A391B724E96E8600E7E8BD /* ⭐️Attributes */,
|
|
||||||
);
|
|
||||||
name = "⭐️Models";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A391B724E96E8600E7E8BD /* ⭐️Attributes */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A391BA24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift */,
|
|
||||||
);
|
|
||||||
name = "⭐️Attributes";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A543D524FB73B2000DC5E3 /* ⭐️ColorsDemo */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A543D624FB7478000DC5E3 /* Classic.ColorsDemo.swift */,
|
|
||||||
B5A543E624FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift */,
|
|
||||||
B5A543EC24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift */,
|
|
||||||
B5A543EE24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift */,
|
|
||||||
B5A543F024FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift */,
|
|
||||||
B5A543F224FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift */,
|
|
||||||
B5A543E824FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift */,
|
|
||||||
B5A543EA24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift */,
|
|
||||||
B5A543D824FB7483000DC5E3 /* Models */,
|
|
||||||
);
|
|
||||||
path = "⭐️ColorsDemo";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A543D824FB7483000DC5E3 /* Models */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A543D924FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld */,
|
|
||||||
B5A543DC24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift */,
|
|
||||||
);
|
|
||||||
name = Models;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A543F424FBF107000DC5E3 /* ⭐️Advanced */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A543F524FBF13A000DC5E3 /* Advanced.swift */,
|
|
||||||
B5A543F8250482EF000DC5E3 /* ⭐️EvolutionDemo */,
|
|
||||||
);
|
|
||||||
path = "⭐️Advanced";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A543F8250482EF000DC5E3 /* ⭐️EvolutionDemo */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A543FA2504840E000DC5E3 /* Advanced.EvolutionDemo.swift */,
|
|
||||||
B5D6F1FD250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift */,
|
|
||||||
B5A543FE250487B1000DC5E3 /* Advanced.EvolutionDemo.MainView.swift */,
|
|
||||||
B5A54400250487C7000DC5E3 /* Advanced.EvolutionDemo.ListView.swift */,
|
|
||||||
B5A54402250487D4000DC5E3 /* Advanced.EvolutionDemo.ItemView.swift */,
|
|
||||||
B5D6F208250E14AA00DF5D2F /* ⭐️Advanced.EvolutionDemo.Migrator.swift */,
|
|
||||||
B5C18F3225138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift */,
|
|
||||||
B54D2F842511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift */,
|
|
||||||
B5A543FD25048794000DC5E3 /* Models */,
|
|
||||||
);
|
|
||||||
path = "⭐️EvolutionDemo";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5A543FD25048794000DC5E3 /* Models */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5A54404250487F5000DC5E3 /* Advanced.EvolutionDemo.CreatureType.swift */,
|
|
||||||
B5D6F20E250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodeld */,
|
|
||||||
B5D6F1F9250E08D200DF5D2F /* V1 */,
|
|
||||||
B5D6F1FA250E0AE000DF5D2F /* V2 */,
|
|
||||||
B5D6F202250E0D9C00DF5D2F /* V3 */,
|
|
||||||
B5D6F203250E0DA400DF5D2F /* V4 */,
|
|
||||||
);
|
|
||||||
name = Models;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5D6F1F9250E08D200DF5D2F /* V1 */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5D6F1F7250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift */,
|
|
||||||
B5A5440625049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift */,
|
|
||||||
B5931B4125124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift */,
|
|
||||||
B54D2F7D25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel */,
|
|
||||||
);
|
|
||||||
name = V1;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5D6F1FA250E0AE000DF5D2F /* V2 */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5D6F1FB250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift */,
|
|
||||||
B5A5440825049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift */,
|
|
||||||
B5931B432512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift */,
|
|
||||||
B54D2F7925119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel */,
|
|
||||||
B54D2F7B251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift */,
|
|
||||||
B5931B4B251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift */,
|
|
||||||
);
|
|
||||||
name = V2;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5D6F202250E0D9C00DF5D2F /* V3 */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5D6F204250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift */,
|
|
||||||
B5A5440A25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift */,
|
|
||||||
B5931B45251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift */,
|
|
||||||
B5931B4925124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift */,
|
|
||||||
);
|
|
||||||
name = V3;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
B5D6F203250E0DA400DF5D2F /* V4 */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B5D6F206250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift */,
|
|
||||||
B5A5440C2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift */,
|
|
||||||
B5931B4725124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift */,
|
|
||||||
);
|
|
||||||
name = V4;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
B5A3911824E5429200E7E8BD /* Demo */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = B5A3912B24E5429300E7E8BD /* Build configuration list for PBXNativeTarget "Demo" */;
|
|
||||||
buildPhases = (
|
|
||||||
B5A3911524E5429200E7E8BD /* Sources */,
|
|
||||||
B5A3911624E5429200E7E8BD /* Frameworks */,
|
|
||||||
B5A3911724E5429200E7E8BD /* Resources */,
|
|
||||||
B5A3917324E698F900E7E8BD /* Embed Frameworks */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = Demo;
|
|
||||||
productName = Demo;
|
|
||||||
productReference = B5A3911924E5429200E7E8BD /* Demo.app */;
|
|
||||||
productType = "com.apple.product-type.application";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
B5A3910F24E5424E00E7E8BD /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
attributes = {
|
|
||||||
LastSwiftUpdateCheck = 1160;
|
|
||||||
LastUpgradeCheck = 1160;
|
|
||||||
TargetAttributes = {
|
|
||||||
B5A3911824E5429200E7E8BD = {
|
|
||||||
CreatedOnToolsVersion = 11.6;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildConfigurationList = B5A3911224E5424E00E7E8BD /* Build configuration list for PBXProject "Demo" */;
|
|
||||||
compatibilityVersion = "Xcode 9.3";
|
|
||||||
developmentRegion = en;
|
|
||||||
hasScannedForEncodings = 0;
|
|
||||||
knownRegions = (
|
|
||||||
en,
|
|
||||||
Base,
|
|
||||||
);
|
|
||||||
mainGroup = B5A3910E24E5424E00E7E8BD;
|
|
||||||
productRefGroup = B5A3911A24E5429200E7E8BD /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
B5A3911824E5429200E7E8BD /* Demo */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
|
||||||
B5A3911724E5429200E7E8BD /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
B5A3912924E5429300E7E8BD /* LaunchScreen.storyboard in Resources */,
|
|
||||||
B5A3912624E5429300E7E8BD /* Preview Assets.xcassets in Resources */,
|
|
||||||
B5A3912324E5429300E7E8BD /* Images.xcassets in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
B5A3911524E5429200E7E8BD /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
B5A543F624FBF13A000DC5E3 /* Advanced.swift in Sources */,
|
|
||||||
B5A3911D24E5429200E7E8BD /* AppDelegate.swift in Sources */,
|
|
||||||
B5A3915924E685EC00E7E8BD /* Classic.swift in Sources */,
|
|
||||||
B5E32C9024FA41F9003F46AD /* ImageDownloader.swift in Sources */,
|
|
||||||
B5A3918024E787D900E7E8BD /* InstructionsView.swift in Sources */,
|
|
||||||
B5A3917C24E6A76C00E7E8BD /* LazyView.swift in Sources */,
|
|
||||||
B5A3913424E6170500E7E8BD /* Menu.swift in Sources */,
|
|
||||||
B5A3915B24E685FE00E7E8BD /* Modern.swift in Sources */,
|
|
||||||
B5A3911F24E5429200E7E8BD /* SceneDelegate.swift in Sources */,
|
|
||||||
B5A543FB2504840E000DC5E3 /* Advanced.EvolutionDemo.swift in Sources */,
|
|
||||||
B5A543D724FB7478000DC5E3 /* Classic.ColorsDemo.swift in Sources */,
|
|
||||||
B5A543DB24FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld in Sources */,
|
|
||||||
B5A3915324E6537F00E7E8BD /* Menu.ItemView.swift in Sources */,
|
|
||||||
B5A3912124E5429200E7E8BD /* Menu.MainView.swift in Sources */,
|
|
||||||
B531EFE724EA762D005F247D /* Menu.PlaceholderView.swift in Sources */,
|
|
||||||
B5A3918F24E7E06500E7E8BD /* Modern.ColorsDemo.swift in Sources */,
|
|
||||||
B5A391B124E96AF600E7E8BD /* Modern.PokedexDemo.swift in Sources */,
|
|
||||||
B5A3918324E7A21800E7E8BD /* Modern.TimeZonesDemo.swift in Sources */,
|
|
||||||
B5A3915E24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift in Sources */,
|
|
||||||
B5A54405250487F5000DC5E3 /* Advanced.EvolutionDemo.CreatureType.swift in Sources */,
|
|
||||||
B54D2F852511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift in Sources */,
|
|
||||||
B5D6F1FE250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift in Sources */,
|
|
||||||
B5A54403250487D5000DC5E3 /* Advanced.EvolutionDemo.ItemView.swift in Sources */,
|
|
||||||
B5A54401250487C7000DC5E3 /* Advanced.EvolutionDemo.ListView.swift in Sources */,
|
|
||||||
B5A543FF250487B1000DC5E3 /* Advanced.EvolutionDemo.MainView.swift in Sources */,
|
|
||||||
B5D6F209250E14AA00DF5D2F /* ⭐️Advanced.EvolutionDemo.Migrator.swift in Sources */,
|
|
||||||
B5C18F3325138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift in Sources */,
|
|
||||||
B5D6F1F8250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift in Sources */,
|
|
||||||
B5D6F210250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodeld in Sources */,
|
|
||||||
B5D6F1FC250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift in Sources */,
|
|
||||||
B5D6F205250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift in Sources */,
|
|
||||||
B5D6F207250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift in Sources */,
|
|
||||||
B5A543E924FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift in Sources */,
|
|
||||||
B5A543E724FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift in Sources */,
|
|
||||||
B5A543F324FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift in Sources */,
|
|
||||||
B5A543EF24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift in Sources */,
|
|
||||||
B5A543ED24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift in Sources */,
|
|
||||||
B5A543DD24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift in Sources */,
|
|
||||||
B5A3919824E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift in Sources */,
|
|
||||||
B5A3919224E7E0C600E7E8BD /* Modern.ColorsDemo.Palette.swift in Sources */,
|
|
||||||
B5A3919E24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift in Sources */,
|
|
||||||
B5A391A024E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift in Sources */,
|
|
||||||
B5A3917E24E7728400E7E8BD /* Modern.PlacemarksDemo.Geocoder.swift in Sources */,
|
|
||||||
B5A3916024E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift in Sources */,
|
|
||||||
B5A3916524E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift in Sources */,
|
|
||||||
B566C8EE24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift in Sources */,
|
|
||||||
B566C8EC24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift in Sources */,
|
|
||||||
B566C8E824F9D406001134A1 /* Modern.PokedexDemo.ListView.swift in Sources */,
|
|
||||||
B566C8EA24F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift in Sources */,
|
|
||||||
B531EFED24EB7453005F247D /* Modern.PokedexDemo.MainView.swift in Sources */,
|
|
||||||
B5A3918C24E7B44B00E7E8BD /* Modern.TimeZonesDemo.ItemView.swift in Sources */,
|
|
||||||
B5A3918A24E7AD1800E7E8BD /* Modern.TimeZonesDemo.ListView.swift in Sources */,
|
|
||||||
B5A3918624E7A54A00E7E8BD /* Modern.TimeZonesDemo.TimeZone.swift in Sources */,
|
|
||||||
B5A543EB24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift in Sources */,
|
|
||||||
B5A543F124FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift in Sources */,
|
|
||||||
B5A391A624E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift in Sources */,
|
|
||||||
B5A3916224E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift in Sources */,
|
|
||||||
B5A391B424E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift in Sources */,
|
|
||||||
B531EFE924EB5A53005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift in Sources */,
|
|
||||||
B5A391BB24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift in Sources */,
|
|
||||||
B531EFEB24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift in Sources */,
|
|
||||||
B5A391B924E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift in Sources */,
|
|
||||||
B5A3918824E7A8F900E7E8BD /* ⭐️Modern.TimeZonesDemo.MainView.swift in Sources */,
|
|
||||||
B5A5440725049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift in Sources */,
|
|
||||||
B5931B4225124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift in Sources */,
|
|
||||||
B54D2F7E25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel in Sources */,
|
|
||||||
B5A5440925049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift in Sources */,
|
|
||||||
B5931B442512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift in Sources */,
|
|
||||||
B54D2F7A25119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel in Sources */,
|
|
||||||
B54D2F7C251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift in Sources */,
|
|
||||||
B5931B4C251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift in Sources */,
|
|
||||||
B5A5440B25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift in Sources */,
|
|
||||||
B5931B46251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift in Sources */,
|
|
||||||
B5931B4A25124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift in Sources */,
|
|
||||||
B5A5440D2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift in Sources */,
|
|
||||||
B5931B4825124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift in Sources */,
|
|
||||||
B5A391AC24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift in Sources */,
|
|
||||||
B5A391AA24E9104300E7E8BD /* Modern.ColorsDemo.UIKit.ItemCell.swift in Sources */,
|
|
||||||
B5A391A424E8F04300E7E8BD /* Modern.ColorsDemo.UIKit.ListView.swift in Sources */,
|
|
||||||
B5A3919A24E8207A00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift in Sources */,
|
|
||||||
B5A3919624E7E4AC00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift in Sources */,
|
|
||||||
B5A3919424E7E36700E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ListView.swift in Sources */,
|
|
||||||
B5A391AE24E9150F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift in Sources */,
|
|
||||||
B5A391A224E8F01F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.ListViewController.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
|
||||||
B5A3912724E5429300E7E8BD /* LaunchScreen.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
B5A3912824E5429300E7E8BD /* Base */,
|
|
||||||
);
|
|
||||||
name = LaunchScreen.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
B5A3911324E5424E00E7E8BD /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
B5A3911424E5424E00E7E8BD /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
B5A3912C24E5429300E7E8BD /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Resources/Preview Content\"";
|
|
||||||
DEVELOPMENT_TEAM = 2JT32EJ5BH;
|
|
||||||
ENABLE_PREVIEWS = YES;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
INFOPLIST_FILE = Info.plist;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
|
||||||
MTL_FAST_MATH = YES;
|
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.Demo;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
B5A3912D24E5429300E7E8BD /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Resources/Preview Content\"";
|
|
||||||
DEVELOPMENT_TEAM = 2JT32EJ5BH;
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_PREVIEWS = YES;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
INFOPLIST_FILE = Info.plist;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
MTL_FAST_MATH = YES;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.Demo;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
B5A3911224E5424E00E7E8BD /* Build configuration list for PBXProject "Demo" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
B5A3911324E5424E00E7E8BD /* Debug */,
|
|
||||||
B5A3911424E5424E00E7E8BD /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
B5A3912B24E5429300E7E8BD /* Build configuration list for PBXNativeTarget "Demo" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
B5A3912C24E5429300E7E8BD /* Debug */,
|
|
||||||
B5A3912D24E5429300E7E8BD /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
|
|
||||||
/* Begin XCVersionGroup section */
|
|
||||||
B5A543D924FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld */ = {
|
|
||||||
isa = XCVersionGroup;
|
|
||||||
children = (
|
|
||||||
B5A543DA24FB7513000DC5E3 /* ColorsDemo.xcdatamodel */,
|
|
||||||
);
|
|
||||||
currentVersion = B5A543DA24FB7513000DC5E3 /* ColorsDemo.xcdatamodel */;
|
|
||||||
path = Classic.ColorsDemo.xcdatamodeld;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
versionGroupType = wrapper.xcdatamodel;
|
|
||||||
};
|
|
||||||
B5D6F20E250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodeld */ = {
|
|
||||||
isa = XCVersionGroup;
|
|
||||||
children = (
|
|
||||||
B5D6F211250E1E7000DF5D2F /* Advanced.EvolutionDemo.V2.xcdatamodel */,
|
|
||||||
B5D6F20F250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodel */,
|
|
||||||
);
|
|
||||||
currentVersion = B5D6F20F250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodel */;
|
|
||||||
path = Advanced.EvolutionDemo.V1.xcdatamodeld;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
versionGroupType = wrapper.xcdatamodel;
|
|
||||||
};
|
|
||||||
/* End XCVersionGroup section */
|
|
||||||
};
|
|
||||||
rootObject = B5A3910F24E5424E00E7E8BD /* Project object */;
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1160"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B5A3911824E5429200E7E8BD"
|
|
||||||
BuildableName = "Demo.app"
|
|
||||||
BlueprintName = "Demo"
|
|
||||||
ReferencedContainer = "container:Demo.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<Testables>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B5A3911824E5429200E7E8BD"
|
|
||||||
BuildableName = "Demo.app"
|
|
||||||
BlueprintName = "Demo"
|
|
||||||
ReferencedContainer = "container:Demo.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "B5A3911824E5429200E7E8BD"
|
|
||||||
BuildableName = "Demo.app"
|
|
||||||
BlueprintName = "Demo"
|
|
||||||
ReferencedContainer = "container:Demo.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<?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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1</string>
|
|
||||||
<key>LSRequiresIPhoneOS</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIApplicationSceneManifest</key>
|
|
||||||
<dict>
|
|
||||||
<key>UIApplicationSupportsMultipleScenes</key>
|
|
||||||
<false/>
|
|
||||||
<key>UISceneConfigurations</key>
|
|
||||||
<dict>
|
|
||||||
<key>UIWindowSceneSessionRoleApplication</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>UISceneConfigurationName</key>
|
|
||||||
<string>Default Configuration</string>
|
|
||||||
<key>UISceneDelegateClassName</key>
|
|
||||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
|
||||||
<string>LaunchScreen</string>
|
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
|
||||||
<array>
|
|
||||||
<string>armv7</string>
|
|
||||||
</array>
|
|
||||||
<key>UIStatusBarTintParameters</key>
|
|
||||||
<dict>
|
|
||||||
<key>UINavigationBar</key>
|
|
||||||
<dict>
|
|
||||||
<key>Style</key>
|
|
||||||
<string>UIBarStyleDefault</string>
|
|
||||||
<key>Translucent</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# coding: utf-8
|
|
||||||
|
|
||||||
task :format do
|
|
||||||
|
|
||||||
require 'xcodeproj'
|
|
||||||
require 'fileutils'
|
|
||||||
|
|
||||||
project_path = 'Demo.xcodeproj'
|
|
||||||
ignore_targets = []
|
|
||||||
|
|
||||||
# http://www.rubydoc.info/github/CocoaPods/Xcodeproj
|
|
||||||
project = Xcodeproj::Project.open(project_path)
|
|
||||||
validTargets = project.targets.select { |target| target.respond_to?(:product_type) }
|
|
||||||
|
|
||||||
validTargets.each do |target|
|
|
||||||
if ignore_targets.include?(target.display_name)
|
|
||||||
next
|
|
||||||
end
|
|
||||||
case target.product_type
|
|
||||||
|
|
||||||
when 'com.apple.product-type.application', 'com.apple.product-type.framework'
|
|
||||||
target.source_build_phase.files.sort! do |f1, f2|
|
|
||||||
result = (f1.display_name.count "+") <=> (f2.display_name.count "+")
|
|
||||||
if result != 0
|
|
||||||
next -result
|
|
||||||
end
|
|
||||||
result = (f1.display_name.count "-") <=> (f2.display_name.count "-")
|
|
||||||
if result != 0
|
|
||||||
next -result
|
|
||||||
end
|
|
||||||
result = (f1.display_name.count ".") <=> (f2.display_name.count ".")
|
|
||||||
if result != 0
|
|
||||||
next result
|
|
||||||
end
|
|
||||||
(f1.display_name <=> f2.display_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
project.save()
|
|
||||||
end
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
|
||||||
<dependencies>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--View Controller-->
|
|
||||||
<scene sceneID="EHf-IW-A2E">
|
|
||||||
<objects>
|
|
||||||
<viewController interfaceStyle="dark" id="01J-lp-oVM" sceneMemberID="viewController">
|
|
||||||
<view key="view" contentMode="scaleToFill" id="Bp2-lt-3DL">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2020 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="Yn3-8H-uzI">
|
|
||||||
<rect key="frame" x="20" y="827" width="374" height="21"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
|
||||||
<nil key="textColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="IrK-8p-pit">
|
|
||||||
<rect key="frame" x="122" y="228.5" width="170" height="170"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" secondItem="IrK-8p-pit" secondAttribute="height" multiplier="1:1" id="WaM-8F-33r"/>
|
|
||||||
<constraint firstAttribute="width" constant="170" id="dlo-1N-ikz"/>
|
|
||||||
</constraints>
|
|
||||||
</imageView>
|
|
||||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="8Vu-0U-3hd">
|
|
||||||
<rect key="frame" x="20" y="418.5" width="374" height="57.5"/>
|
|
||||||
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
|
|
||||||
<nil key="textColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
</subviews>
|
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="Yn3-8H-uzI" firstAttribute="leading" secondItem="Bp2-lt-3DL" secondAttribute="leading" constant="20" symbolic="YES" id="7Dq-xP-k2v"/>
|
|
||||||
<constraint firstItem="IrK-8p-pit" firstAttribute="centerY" secondItem="Bp2-lt-3DL" secondAttribute="centerY" multiplier="0.7" id="HUz-XL-l27"/>
|
|
||||||
<constraint firstItem="IrK-8p-pit" firstAttribute="centerX" secondItem="Bp2-lt-3DL" secondAttribute="centerX" id="TSf-yM-hl1"/>
|
|
||||||
<constraint firstAttribute="centerX" secondItem="8Vu-0U-3hd" secondAttribute="centerX" id="TX2-HT-cKs"/>
|
|
||||||
<constraint firstItem="Z3i-EZ-UGs" firstAttribute="bottom" secondItem="Yn3-8H-uzI" secondAttribute="bottom" constant="14" id="hAb-SJ-Qnm"/>
|
|
||||||
<constraint firstAttribute="centerX" secondItem="Yn3-8H-uzI" secondAttribute="centerX" id="pNf-eo-RXZ"/>
|
|
||||||
<constraint firstItem="8Vu-0U-3hd" firstAttribute="leading" secondItem="Bp2-lt-3DL" secondAttribute="leading" constant="20" symbolic="YES" id="pef-yD-C5e"/>
|
|
||||||
<constraint firstItem="8Vu-0U-3hd" firstAttribute="top" secondItem="IrK-8p-pit" secondAttribute="bottom" constant="20" id="xQP-tq-hNL"/>
|
|
||||||
</constraints>
|
|
||||||
<viewLayoutGuide key="safeArea" id="Z3i-EZ-UGs"/>
|
|
||||||
</view>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="53" y="375"/>
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
<resources>
|
|
||||||
<image name="CoreStoreIcon" width="170" height="170"/>
|
|
||||||
</resources>
|
|
||||||
</document>
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "3x",
|
|
||||||
"size" : "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "3x",
|
|
||||||
"size" : "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "3x",
|
|
||||||
"size" : "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Icon-60@2x.png",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "60x60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Icon-60@3x-1.png",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"scale" : "3x",
|
|
||||||
"size" : "60x60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "20x20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "29x29"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "40x40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Icon-76.png",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "76x76"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Icon-76@2x.png",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "76x76"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Icon-83.5@2x.png",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "83.5x83.5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Mask + Oval 1 + Oval 1 + Oval 1.png",
|
|
||||||
"idiom" : "ios-marketing",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "car",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "60x60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Icon-60@3x.png",
|
|
||||||
"idiom" : "car",
|
|
||||||
"scale" : "3x",
|
|
||||||
"size" : "60x60"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 118 KiB |
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "CoreStoreIcon.pdf",
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "original"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
// MARK: - AppDelegate
|
|
||||||
|
|
||||||
@UIApplicationMain
|
|
||||||
@objc final class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
||||||
|
|
||||||
// MARK: UIApplicationDelegate
|
|
||||||
|
|
||||||
@objc dynamic func application(
|
|
||||||
_ application: UIApplication,
|
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
||||||
) -> Bool {
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc dynamic func application(
|
|
||||||
_ application: UIApplication,
|
|
||||||
configurationForConnecting connectingSceneSession: UISceneSession,
|
|
||||||
options: UIScene.ConnectionOptions
|
|
||||||
) -> UISceneConfiguration {
|
|
||||||
|
|
||||||
return UISceneConfiguration(
|
|
||||||
name: "Default Configuration",
|
|
||||||
sessionRole: connectingSceneSession.role
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import Combine
|
|
||||||
|
|
||||||
// MARK: - ImageDownloader
|
|
||||||
|
|
||||||
final class ImageDownloader: ObservableObject {
|
|
||||||
|
|
||||||
// MARK: FilePrivate
|
|
||||||
|
|
||||||
private(set) var image: UIImage?
|
|
||||||
|
|
||||||
let url: URL?
|
|
||||||
|
|
||||||
init(url: URL?) {
|
|
||||||
|
|
||||||
self.url = url
|
|
||||||
guard let url = url else {
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let image = Self.cache[url] {
|
|
||||||
|
|
||||||
self.image = image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchImage(completion: @escaping (UIImage) -> Void = { _ in }) {
|
|
||||||
|
|
||||||
guard let url = url else {
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let image = Self.cache[url] {
|
|
||||||
|
|
||||||
self.objectWillChange.send()
|
|
||||||
self.image = image
|
|
||||||
completion(image)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.cancellable = URLSession.shared
|
|
||||||
.dataTaskPublisher(for: url)
|
|
||||||
.receive(on: DispatchQueue.main)
|
|
||||||
.sink(
|
|
||||||
receiveCompletion: { _ in },
|
|
||||||
receiveValue: { output in
|
|
||||||
|
|
||||||
if let image = UIImage(data: output.data) {
|
|
||||||
|
|
||||||
Self.cache[url] = image
|
|
||||||
self.objectWillChange.send()
|
|
||||||
self.image = image
|
|
||||||
completion(image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private static var cache: [URL: UIImage] = [:]
|
|
||||||
|
|
||||||
private var cancellable: AnyCancellable?
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - InstructionsView
|
|
||||||
|
|
||||||
struct InstructionsView: View {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
init(_ rows: (header: String, description: String)...) {
|
|
||||||
|
|
||||||
self.rows = rows.map({ .init(header: $0, description: $1) })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ZStack(alignment: .center) {
|
|
||||||
Color.white
|
|
||||||
.cornerRadius(10)
|
|
||||||
.shadow(color: Color(.sRGB, white: 0.5, opacity: 0.3), radius: 2, x: 1, y: 1)
|
|
||||||
VStack(alignment: .leading, spacing: 3) {
|
|
||||||
ForEach(self.rows, id: \.header) { row in
|
|
||||||
HStack(alignment: .firstTextBaseline, spacing: 5) {
|
|
||||||
Text(row.header)
|
|
||||||
.font(.callout)
|
|
||||||
.fontWeight(.bold)
|
|
||||||
Text(row.description)
|
|
||||||
.font(.footnote)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.foregroundColor(Color(.sRGB, white: 0, opacity: 0.8))
|
|
||||||
.padding(.horizontal, 10)
|
|
||||||
.padding(.vertical, 4)
|
|
||||||
}
|
|
||||||
.fixedSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let rows: [InstructionsView.Row]
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Row
|
|
||||||
|
|
||||||
struct Row: Hashable {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
let header: String
|
|
||||||
let description: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - LazyView
|
|
||||||
|
|
||||||
struct LazyView<Content: View>: View {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
init(_ load: @escaping () -> Content) {
|
|
||||||
|
|
||||||
self.load = load
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: Content {
|
|
||||||
|
|
||||||
self.load()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let load: () -> Content
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - Menu
|
|
||||||
|
|
||||||
extension Menu {
|
|
||||||
|
|
||||||
// MARK: - Menu.ItemView
|
|
||||||
|
|
||||||
struct ItemView<Destination: View>: View {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
init(
|
|
||||||
title: String,
|
|
||||||
subtitle: String? = nil,
|
|
||||||
destination: @escaping () -> Destination
|
|
||||||
) {
|
|
||||||
self.title = title
|
|
||||||
self.subtitle = subtitle
|
|
||||||
self.destination = destination
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationLink(destination: LazyView(self.destination)) {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text(self.title)
|
|
||||||
.font(.headline)
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
self.subtitle.map {
|
|
||||||
Text($0)
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: FilePrivate
|
|
||||||
|
|
||||||
fileprivate let title: String
|
|
||||||
fileprivate let subtitle: String?
|
|
||||||
fileprivate let destination: () -> Destination
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct _Demo_Menu_ItemView_Preview: PreviewProvider {
|
|
||||||
|
|
||||||
// MARK: PreviewProvider
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Item Title",
|
|
||||||
subtitle: "A subtitle caption for this item",
|
|
||||||
destination: {
|
|
||||||
Color.blue
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Menu
|
|
||||||
|
|
||||||
extension Menu {
|
|
||||||
|
|
||||||
// MARK: - Menu.MainView
|
|
||||||
|
|
||||||
struct MainView: View {
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationView {
|
|
||||||
List {
|
|
||||||
Section(header: Text("Modern (CoreStoreObject subclasses)")) {
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Placemarks",
|
|
||||||
subtitle: "Making changes using Transactions",
|
|
||||||
destination: {
|
|
||||||
Modern.PlacemarksDemo.MainView()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Time Zones",
|
|
||||||
subtitle: "Fetching objects and Querying raw values",
|
|
||||||
destination: {
|
|
||||||
Modern.TimeZonesDemo.MainView()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Colors (UIKit)",
|
|
||||||
subtitle: "Observing list changes and single-object changes using DiffableDataSources",
|
|
||||||
destination: {
|
|
||||||
Modern.ColorsDemo.MainView(
|
|
||||||
listView: { listPublisher, onPaletteTapped in
|
|
||||||
Modern.ColorsDemo.UIKit.ListView(
|
|
||||||
listPublisher: listPublisher,
|
|
||||||
onPaletteTapped: onPaletteTapped
|
|
||||||
)
|
|
||||||
.edgesIgnoringSafeArea(.all)
|
|
||||||
},
|
|
||||||
detailView: { objectPublisher in
|
|
||||||
Modern.ColorsDemo.UIKit.DetailView(objectPublisher)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Colors (SwiftUI)",
|
|
||||||
subtitle: "Observing list changes and single-object changes using SwiftUI bindings",
|
|
||||||
destination: {
|
|
||||||
Modern.ColorsDemo.MainView(
|
|
||||||
listView: { listPublisher, onPaletteTapped in
|
|
||||||
Modern.ColorsDemo.SwiftUI.ListView(
|
|
||||||
listPublisher: listPublisher,
|
|
||||||
onPaletteTapped: onPaletteTapped
|
|
||||||
)
|
|
||||||
},
|
|
||||||
detailView: { objectPublisher in
|
|
||||||
Modern.ColorsDemo.SwiftUI.DetailView(objectPublisher)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Pokedex API",
|
|
||||||
subtitle: "Importing JSON data from external source",
|
|
||||||
destination: {
|
|
||||||
Modern.PokedexDemo.MainView()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Section(header: Text("Classic (NSManagedObject subclasses)")) {
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Colors",
|
|
||||||
subtitle: "Observing list changes and single-object changes using ListMonitor",
|
|
||||||
destination: {
|
|
||||||
Classic.ColorsDemo.MainView()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Section(header: Text("Advanced")) {
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Accounts",
|
|
||||||
subtitle: "Switching between multiple persistent stores",
|
|
||||||
destination: { EmptyView() }
|
|
||||||
)
|
|
||||||
.disabled(true)
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Evolution",
|
|
||||||
subtitle: "Migrating and reverse-migrating stores",
|
|
||||||
destination: {
|
|
||||||
Advanced.EvolutionDemo.MainView()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Menu.ItemView(
|
|
||||||
title: "Logger",
|
|
||||||
subtitle: "Implementing a custom logger",
|
|
||||||
destination: { EmptyView() }
|
|
||||||
)
|
|
||||||
.disabled(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.listStyle(GroupedListStyle())
|
|
||||||
.navigationBarTitle("CoreStore Demos")
|
|
||||||
Menu.PlaceholderView()
|
|
||||||
}
|
|
||||||
.navigationViewStyle(DoubleColumnNavigationViewStyle())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct _Demo_Menu_MainView_Preview: PreviewProvider {
|
|
||||||
|
|
||||||
// MARK: PreviewProvider
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
|
|
||||||
Menu.MainView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import CoreStore
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - Menu
|
|
||||||
|
|
||||||
extension Menu {
|
|
||||||
|
|
||||||
// MARK: - Menu.PlaceholderView
|
|
||||||
|
|
||||||
struct PlaceholderView: UIViewControllerRepresentable {
|
|
||||||
|
|
||||||
// MARK: UIViewControllerRepresentable
|
|
||||||
|
|
||||||
typealias UIViewControllerType = UIViewController
|
|
||||||
|
|
||||||
func makeUIViewController(context: Self.Context) -> UIViewControllerType {
|
|
||||||
|
|
||||||
return UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController()!
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Self.Context) {}
|
|
||||||
|
|
||||||
static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Void) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct _Demo_Menu_PlaceholderView_Preview: PreviewProvider {
|
|
||||||
|
|
||||||
// MARK: PreviewProvider
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
|
|
||||||
return Menu.PlaceholderView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Menu
|
|
||||||
|
|
||||||
enum Menu {}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
// MARK: - SceneDelegate
|
|
||||||
|
|
||||||
@objc final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
||||||
|
|
||||||
// MARK: UIWindowSceneDelegate
|
|
||||||
|
|
||||||
@objc dynamic var window: UIWindow?
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: UISceneDelegate
|
|
||||||
|
|
||||||
@objc dynamic func scene(
|
|
||||||
_ scene: UIScene,
|
|
||||||
willConnectTo session: UISceneSession,
|
|
||||||
options connectionOptions: UIScene.ConnectionOptions
|
|
||||||
) {
|
|
||||||
|
|
||||||
guard case let scene as UIWindowScene = scene else {
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let window = UIWindow(windowScene: scene)
|
|
||||||
window.rootViewController = UIHostingController(
|
|
||||||
rootView: Menu.MainView()
|
|
||||||
)
|
|
||||||
self.window = window
|
|
||||||
window.makeKeyAndVisible()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
// MARK: - Advanced
|
|
||||||
|
|
||||||
/**
|
|
||||||
Sample application of complex use cases
|
|
||||||
*/
|
|
||||||
enum Advanced {}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import CoreStore
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
typealias CreatureType = Advanced_EvolutionDemo_CreatureType
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.CreatureType
|
|
||||||
|
|
||||||
protocol Advanced_EvolutionDemo_CreatureType: DynamicObject, CustomStringConvertible {
|
|
||||||
|
|
||||||
var dnaCode: Int64 { get set }
|
|
||||||
|
|
||||||
static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource
|
|
||||||
|
|
||||||
static func count(in transaction: BaseDataTransaction) throws -> Int
|
|
||||||
|
|
||||||
static func create(in transaction: BaseDataTransaction) -> Self
|
|
||||||
|
|
||||||
func mutate(in transaction: BaseDataTransaction)
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import CoreStore
|
|
||||||
import Combine
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.CreaturesDataSource
|
|
||||||
|
|
||||||
/**
|
|
||||||
A type-erasing adapter to support different `ListPublisher` types
|
|
||||||
*/
|
|
||||||
final class CreaturesDataSource: ObservableObject {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
init<T: NSManagedObject & Advanced.EvolutionDemo.CreatureType>(
|
|
||||||
listPublisher: ListPublisher<T>,
|
|
||||||
dataStack: DataStack
|
|
||||||
) {
|
|
||||||
|
|
||||||
self.numberOfItems = {
|
|
||||||
listPublisher.snapshot.numberOfItems
|
|
||||||
}
|
|
||||||
self.itemDescriptionAtIndex = { index in
|
|
||||||
listPublisher.snapshot[index].object?.description
|
|
||||||
}
|
|
||||||
self.addItems = { count in
|
|
||||||
|
|
||||||
dataStack.perform(
|
|
||||||
asynchronous: { transaction in
|
|
||||||
|
|
||||||
let nextDNACode = try transaction.fetchCount(From<T>())
|
|
||||||
for offset in 0 ..< count {
|
|
||||||
|
|
||||||
let object = transaction.create(Into<T>())
|
|
||||||
object.dnaCode = .init(nextDNACode + offset)
|
|
||||||
object.mutate(in: transaction)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
completion: { _ in }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.mutateItemAtIndex = { index in
|
|
||||||
|
|
||||||
let object = listPublisher.snapshot[index]
|
|
||||||
dataStack.perform(
|
|
||||||
asynchronous: { transaction in
|
|
||||||
|
|
||||||
object
|
|
||||||
.asEditable(in: transaction)?
|
|
||||||
.mutate(in: transaction)
|
|
||||||
},
|
|
||||||
completion: { _ in }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.deleteAllItems = {
|
|
||||||
|
|
||||||
dataStack.perform(
|
|
||||||
asynchronous: { transaction in
|
|
||||||
|
|
||||||
try transaction.deleteAll(From<T>())
|
|
||||||
},
|
|
||||||
completion: { _ in }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
listPublisher.addObserver(self) { [weak self] (listPublisher) in
|
|
||||||
|
|
||||||
self?.objectWillChange.send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init<T: CoreStoreObject & Advanced.EvolutionDemo.CreatureType>(
|
|
||||||
listPublisher: ListPublisher<T>,
|
|
||||||
dataStack: DataStack
|
|
||||||
) {
|
|
||||||
|
|
||||||
self.numberOfItems = {
|
|
||||||
listPublisher.snapshot.numberOfItems
|
|
||||||
}
|
|
||||||
self.itemDescriptionAtIndex = { index in
|
|
||||||
listPublisher.snapshot[index].object?.description
|
|
||||||
}
|
|
||||||
self.addItems = { count in
|
|
||||||
|
|
||||||
dataStack.perform(
|
|
||||||
asynchronous: { transaction in
|
|
||||||
|
|
||||||
let nextDNACode = try transaction.fetchCount(From<T>())
|
|
||||||
for offset in 0 ..< count {
|
|
||||||
|
|
||||||
let object = transaction.create(Into<T>())
|
|
||||||
object.dnaCode = .init(nextDNACode + offset)
|
|
||||||
object.mutate(in: transaction)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
completion: { _ in }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.mutateItemAtIndex = { index in
|
|
||||||
|
|
||||||
let object = listPublisher.snapshot[index]
|
|
||||||
dataStack.perform(
|
|
||||||
asynchronous: { transaction in
|
|
||||||
|
|
||||||
object
|
|
||||||
.asEditable(in: transaction)?
|
|
||||||
.mutate(in: transaction)
|
|
||||||
},
|
|
||||||
completion: { _ in }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.deleteAllItems = {
|
|
||||||
|
|
||||||
dataStack.perform(
|
|
||||||
asynchronous: { transaction in
|
|
||||||
|
|
||||||
try transaction.deleteAll(From<T>())
|
|
||||||
},
|
|
||||||
completion: { _ in }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
listPublisher.addObserver(self) { [weak self] (listPublisher) in
|
|
||||||
|
|
||||||
self?.objectWillChange.send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func numberOfCreatures() -> Int {
|
|
||||||
|
|
||||||
return self.numberOfItems()
|
|
||||||
}
|
|
||||||
|
|
||||||
func creatureDescription(at index: Int) -> String? {
|
|
||||||
|
|
||||||
return self.itemDescriptionAtIndex(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mutate(at index: Int) {
|
|
||||||
|
|
||||||
self.mutateItemAtIndex(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
func add(count: Int) {
|
|
||||||
|
|
||||||
self.addItems(count)
|
|
||||||
}
|
|
||||||
|
|
||||||
func clear() {
|
|
||||||
|
|
||||||
self.deleteAllItems()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let numberOfItems: () -> Int
|
|
||||||
private let itemDescriptionAtIndex: (Int) -> String?
|
|
||||||
private let mutateItemAtIndex: (Int) -> Void
|
|
||||||
private let addItems: (Int) -> Void
|
|
||||||
private let deleteAllItems: () -> Void
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - AdvancedEvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
// MARK: - GeologicalPeriod
|
|
||||||
|
|
||||||
enum GeologicalPeriod: RawRepresentable, CaseIterable, Hashable, CustomStringConvertible {
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
case ageOfInvertebrates
|
|
||||||
case ageOfFishes
|
|
||||||
case ageOfReptiles
|
|
||||||
case ageOfMammals
|
|
||||||
|
|
||||||
var version: ModelVersion {
|
|
||||||
|
|
||||||
return self.rawValue
|
|
||||||
}
|
|
||||||
|
|
||||||
var creatureType: Advanced.EvolutionDemo.CreatureType.Type {
|
|
||||||
|
|
||||||
switch self {
|
|
||||||
|
|
||||||
case .ageOfInvertebrates:
|
|
||||||
return Advanced.EvolutionDemo.V1.Creature.self
|
|
||||||
case .ageOfFishes:
|
|
||||||
return Advanced.EvolutionDemo.V2.Creature.self
|
|
||||||
case .ageOfReptiles:
|
|
||||||
return Advanced.EvolutionDemo.V3.Creature.self
|
|
||||||
case .ageOfMammals:
|
|
||||||
return Advanced.EvolutionDemo.V4.Creature.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: CustomStringConvertible
|
|
||||||
|
|
||||||
var description: String {
|
|
||||||
|
|
||||||
switch self {
|
|
||||||
|
|
||||||
case .ageOfInvertebrates:
|
|
||||||
return "Invertebrates"
|
|
||||||
case .ageOfFishes:
|
|
||||||
return "Fishes"
|
|
||||||
case .ageOfReptiles:
|
|
||||||
return "Reptiles"
|
|
||||||
case .ageOfMammals:
|
|
||||||
return "Mammals"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: RawRepresentable
|
|
||||||
|
|
||||||
typealias RawValue = ModelVersion
|
|
||||||
|
|
||||||
var rawValue: ModelVersion {
|
|
||||||
|
|
||||||
switch self {
|
|
||||||
|
|
||||||
case .ageOfInvertebrates:
|
|
||||||
return Advanced.EvolutionDemo.V1.name
|
|
||||||
case .ageOfFishes:
|
|
||||||
return Advanced.EvolutionDemo.V2.name
|
|
||||||
case .ageOfReptiles:
|
|
||||||
return Advanced.EvolutionDemo.V3.name
|
|
||||||
case .ageOfMammals:
|
|
||||||
return Advanced.EvolutionDemo.V4.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init?(rawValue: ModelVersion) {
|
|
||||||
|
|
||||||
switch rawValue {
|
|
||||||
|
|
||||||
case Advanced.EvolutionDemo.V1.name:
|
|
||||||
self = .ageOfInvertebrates
|
|
||||||
case Advanced.EvolutionDemo.V2.name:
|
|
||||||
self = .ageOfFishes
|
|
||||||
case Advanced.EvolutionDemo.V3.name:
|
|
||||||
self = .ageOfReptiles
|
|
||||||
case Advanced.EvolutionDemo.V4.name:
|
|
||||||
self = .ageOfMammals
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.ItemView
|
|
||||||
|
|
||||||
struct ItemView: View {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
init(description: String?, mutate: @escaping () -> Void) {
|
|
||||||
|
|
||||||
self.description = description
|
|
||||||
self.mutate = mutate
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack {
|
|
||||||
Text(self.description ?? "")
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
Spacer()
|
|
||||||
Button(
|
|
||||||
action: self.mutate,
|
|
||||||
label: {
|
|
||||||
Text("Mutate")
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
.fontWeight(.bold)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.buttonStyle(PlainButtonStyle())
|
|
||||||
}
|
|
||||||
.disabled(self.description == nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: FilePrivate
|
|
||||||
|
|
||||||
fileprivate let description: String?
|
|
||||||
fileprivate let mutate: () -> Void
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct _Demo_Advanced_EvolutionDemo_ItemView_Preview: PreviewProvider {
|
|
||||||
|
|
||||||
// MARK: PreviewProvider
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
Advanced.EvolutionDemo.ItemView(
|
|
||||||
description: """
|
|
||||||
dnaCode: 123
|
|
||||||
numberOfLimbs: 4
|
|
||||||
hasVertebrae: true
|
|
||||||
hasHead: true
|
|
||||||
hasTail: true
|
|
||||||
habitat: land
|
|
||||||
hasWings: false
|
|
||||||
""",
|
|
||||||
mutate: {}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import CoreStore
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.ListView
|
|
||||||
|
|
||||||
struct ListView: View {
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
let dataSource = self.dataSource
|
|
||||||
return List {
|
|
||||||
ForEach(0 ..< dataSource.numberOfCreatures(), id: \.self) { (index) in
|
|
||||||
Advanced.EvolutionDemo.ItemView(
|
|
||||||
description: dataSource.creatureDescription(at: index),
|
|
||||||
mutate: {
|
|
||||||
|
|
||||||
dataSource.mutate(at: index)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.listStyle(PlainListStyle())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
init(
|
|
||||||
period: Advanced.EvolutionDemo.GeologicalPeriod,
|
|
||||||
dataStack: DataStack,
|
|
||||||
dataSource: Advanced.EvolutionDemo.CreaturesDataSource
|
|
||||||
) {
|
|
||||||
|
|
||||||
self.period = period
|
|
||||||
self.dataStack = dataStack
|
|
||||||
self.dataSource = dataSource
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let period: Advanced.EvolutionDemo.GeologicalPeriod
|
|
||||||
|
|
||||||
private let dataStack: DataStack
|
|
||||||
|
|
||||||
@ObservedObject
|
|
||||||
private var dataSource: Advanced.EvolutionDemo.CreaturesDataSource
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct _Demo_Advanced_EvolutionDemo_ListView_Preview: PreviewProvider {
|
|
||||||
|
|
||||||
// MARK: PreviewProvider
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
|
|
||||||
let dataStack = DataStack(
|
|
||||||
CoreStoreSchema(
|
|
||||||
modelVersion: Advanced.EvolutionDemo.V4.name,
|
|
||||||
entities: [
|
|
||||||
Entity<Advanced.EvolutionDemo.V4.Creature>("Creature")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
try! dataStack.addStorageAndWait(
|
|
||||||
SQLiteStore(fileName: "Advanced.EvolutionDemo.ListView.Preview.sqlite")
|
|
||||||
)
|
|
||||||
try! dataStack.perform(
|
|
||||||
synchronous: { transaction in
|
|
||||||
|
|
||||||
for dnaCode in 0 ..< 10 as Range<Int64> {
|
|
||||||
|
|
||||||
let object = transaction.create(Into<Advanced.EvolutionDemo.V4.Creature>())
|
|
||||||
object.dnaCode = dnaCode
|
|
||||||
object.mutate(in: transaction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return Advanced.EvolutionDemo.ListView(
|
|
||||||
period: .ageOfMammals,
|
|
||||||
dataStack: dataStack,
|
|
||||||
dataSource: Advanced.EvolutionDemo.V4.Creature.dataSource(in: dataStack)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import CoreStore
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.MainView
|
|
||||||
|
|
||||||
struct MainView: View {
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
let migrator = self.migrator
|
|
||||||
let listView: AnyView
|
|
||||||
if let current = migrator.current {
|
|
||||||
|
|
||||||
listView = AnyView(
|
|
||||||
Advanced.EvolutionDemo.ListView(
|
|
||||||
period: current.period,
|
|
||||||
dataStack: current.dataStack,
|
|
||||||
dataSource: current.dataSource
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
listView = AnyView(
|
|
||||||
Advanced.EvolutionDemo.ProgressView(progress: migrator.progress)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return VStack(spacing: 0) {
|
|
||||||
HStack(alignment: .center, spacing: 0) {
|
|
||||||
Text("Age of")
|
|
||||||
.padding(.trailing)
|
|
||||||
Picker(selection: self.$migrator.currentPeriod, label: EmptyView()) {
|
|
||||||
ForEach(Advanced.EvolutionDemo.GeologicalPeriod.allCases, id: \.self) { period in
|
|
||||||
Text(period.description).tag(period)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.pickerStyle(SegmentedPickerStyle())
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
listView
|
|
||||||
.edgesIgnoringSafeArea(.vertical)
|
|
||||||
}
|
|
||||||
.navigationBarTitle("Evolution")
|
|
||||||
.disabled(migrator.isBusy || migrator.current == nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
@ObservedObject
|
|
||||||
private var migrator: Advanced.EvolutionDemo.Migrator = .init()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct _Demo_Advanced_EvolutionDemo_MainView_Preview: PreviewProvider {
|
|
||||||
|
|
||||||
// MARK: PreviewProvider
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
|
|
||||||
Advanced.EvolutionDemo.MainView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.ProgressView
|
|
||||||
|
|
||||||
struct ProgressView: View {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
init(progress: Progress?) {
|
|
||||||
|
|
||||||
self.progressObserver = .init(progress)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: View
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
|
|
||||||
guard self.progressObserver.isMigrating else {
|
|
||||||
|
|
||||||
return AnyView(
|
|
||||||
VStack(alignment: .center) {
|
|
||||||
Text("Preparing creatures...")
|
|
||||||
.padding()
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return AnyView(
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text("Migrating: \(self.progressObserver.localizedDescription)")
|
|
||||||
.font(.headline)
|
|
||||||
.padding([.top, .horizontal])
|
|
||||||
Text("Progressive step: \(self.progressObserver.localizedAdditionalDescription)")
|
|
||||||
.font(.subheadline)
|
|
||||||
.padding(.horizontal)
|
|
||||||
GeometryReader { geometry in
|
|
||||||
ZStack(alignment: .leading) {
|
|
||||||
Color.gray
|
|
||||||
.opacity(0.2)
|
|
||||||
.frame(width: geometry.size.width, height: 8)
|
|
||||||
.cornerRadius(4.0)
|
|
||||||
Color.blue
|
|
||||||
.frame(
|
|
||||||
width: geometry.size.width
|
|
||||||
* self.progressObserver.fractionCompleted,
|
|
||||||
height: 8
|
|
||||||
)
|
|
||||||
.cornerRadius(4.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
.padding()
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: FilePrivate
|
|
||||||
|
|
||||||
@ObservedObject
|
|
||||||
private var progressObserver: ProgressObserver
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - ProgressObserver
|
|
||||||
|
|
||||||
fileprivate final class ProgressObserver: ObservableObject {
|
|
||||||
|
|
||||||
private(set) var fractionCompleted: CGFloat = 0
|
|
||||||
private(set) var localizedDescription: String = ""
|
|
||||||
private(set) var localizedAdditionalDescription: String = ""
|
|
||||||
|
|
||||||
var isMigrating: Bool {
|
|
||||||
|
|
||||||
return self.progress != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
init(_ progress: Progress?) {
|
|
||||||
|
|
||||||
self.progress = progress
|
|
||||||
|
|
||||||
progress?.setProgressHandler { [weak self] (progess) in
|
|
||||||
|
|
||||||
guard let self = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.objectWillChange.send()
|
|
||||||
self.fractionCompleted = CGFloat(progress?.fractionCompleted ?? 0)
|
|
||||||
self.localizedDescription = progress?.localizedDescription ?? ""
|
|
||||||
self.localizedAdditionalDescription = progress?.localizedAdditionalDescription ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let progress: Progress?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct _Demo_Advanced_EvolutionDemo_ProgressView_Preview: PreviewProvider {
|
|
||||||
|
|
||||||
// MARK: PreviewProvider
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
let progress = Progress(totalUnitCount: 10)
|
|
||||||
progress.completedUnitCount = 3
|
|
||||||
return Advanced.EvolutionDemo.ProgressView(
|
|
||||||
progress: progress
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.V1.Creature
|
|
||||||
|
|
||||||
@objc(Advanced_EvolutionDemo_V1_Creature)
|
|
||||||
final class Advanced_EvolutionDemo_V1_Creature: NSManagedObject, Advanced.EvolutionDemo.CreatureType {
|
|
||||||
|
|
||||||
@NSManaged
|
|
||||||
dynamic var dnaCode: Int64
|
|
||||||
|
|
||||||
@NSManaged
|
|
||||||
dynamic var numberOfFlagella: Int32
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: CustomStringConvertible
|
|
||||||
|
|
||||||
override var description: String {
|
|
||||||
|
|
||||||
return """
|
|
||||||
dnaCode: \(self.dnaCode)
|
|
||||||
numberOfFlagella: \(self.numberOfFlagella)
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Advanced.EvolutionDemo.CreatureType
|
|
||||||
|
|
||||||
static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource {
|
|
||||||
|
|
||||||
return .init(
|
|
||||||
listPublisher: dataStack.publishList(
|
|
||||||
From<Advanced.EvolutionDemo.V1.Creature>()
|
|
||||||
.orderBy(.descending(\.dnaCode))
|
|
||||||
),
|
|
||||||
dataStack: dataStack
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func count(in transaction: BaseDataTransaction) throws -> Int {
|
|
||||||
|
|
||||||
return try transaction.fetchCount(
|
|
||||||
From<Advanced.EvolutionDemo.V1.Creature>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V1.Creature {
|
|
||||||
|
|
||||||
return transaction.create(
|
|
||||||
Into<Advanced.EvolutionDemo.V1.Creature>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mutate(in transaction: BaseDataTransaction) {
|
|
||||||
|
|
||||||
self.numberOfFlagella = .random(in: 1...200)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.V1
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo.V1 {
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.V1.FromV2
|
|
||||||
|
|
||||||
enum FromV2 {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
static var mapping: XcodeSchemaMappingProvider {
|
|
||||||
|
|
||||||
return XcodeSchemaMappingProvider(
|
|
||||||
from: Advanced.EvolutionDemo.V2.name,
|
|
||||||
to: Advanced.EvolutionDemo.V1.name,
|
|
||||||
mappingModelBundle: Bundle(for: Advanced.EvolutionDemo.V1.Creature.self)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo
|
|
||||||
|
|
||||||
extension Advanced.EvolutionDemo {
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.V1
|
|
||||||
|
|
||||||
/**
|
|
||||||
Namespace for V1 models (`Advanced.EvolutionDemo.GeologicalPeriod.ageOfInvertebrates`)
|
|
||||||
*/
|
|
||||||
enum V1 {
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
static let name: ModelVersion = "Advanced.EvolutionDemo.V1"
|
|
||||||
|
|
||||||
typealias Creature = Advanced_EvolutionDemo_V1_Creature
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?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>_XCCurrentVersionName</key>
|
|
||||||
<string>Advanced.EvolutionDemo.V1.xcdatamodel</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19F101" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
|
||||||
<entity name="Creature" representedClassName="Advanced_EvolutionDemo_V1_Creature" syncable="YES">
|
|
||||||
<attribute name="dnaCode" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="numberOfFlagella" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="YES"/>
|
|
||||||
</entity>
|
|
||||||
<elements>
|
|
||||||
<element name="Creature" positionX="-27" positionY="18" width="128" height="73"/>
|
|
||||||
</elements>
|
|
||||||
</model>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19F101" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
|
||||||
<entity name="Creature" representedClassName="Advanced_EvolutionDemo_V2_Creature" syncable="YES">
|
|
||||||
<attribute name="dnaCode" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="hasHead" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="hasTail" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="hasVertebrae" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="YES"/>
|
|
||||||
</entity>
|
|
||||||
<elements>
|
|
||||||
<element name="Creature" positionX="-9" positionY="36" width="128" height="118"/>
|
|
||||||
</elements>
|
|
||||||
</model>
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
//
|
|
||||||
// Demo
|
|
||||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import CoreStore
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Advanced.EvolutionDemo.V2.Creature
|
|
||||||
|
|
||||||
@objc(Advanced_EvolutionDemo_V2_Creature)
|
|
||||||
final class Advanced_EvolutionDemo_V2_Creature: NSManagedObject, Advanced.EvolutionDemo.CreatureType {
|
|
||||||
|
|
||||||
@NSManaged
|
|
||||||
dynamic var dnaCode: Int64
|
|
||||||
|
|
||||||
@NSManaged
|
|
||||||
dynamic var numberOfFlippers: Int32
|
|
||||||
|
|
||||||
@NSManaged
|
|
||||||
dynamic var hasVertebrae: Bool
|
|
||||||
|
|
||||||
@NSManaged
|
|
||||||
dynamic var hasHead: Bool
|
|
||||||
|
|
||||||
@NSManaged
|
|
||||||
dynamic var hasTail: Bool
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: CustomStringConvertible
|
|
||||||
|
|
||||||
override var description: String {
|
|
||||||
|
|
||||||
return """
|
|
||||||
dnaCode: \(self.dnaCode)
|
|
||||||
numberOfFlippers: \(self.numberOfFlippers)
|
|
||||||
hasVertebrae: \(self.hasVertebrae)
|
|
||||||
hasHead: \(self.hasHead)
|
|
||||||
hasTail: \(self.hasTail)
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Advanced.EvolutionDemo.CreatureType
|
|
||||||
|
|
||||||
static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource {
|
|
||||||
|
|
||||||
return .init(
|
|
||||||
listPublisher: dataStack.publishList(
|
|
||||||
From<Advanced.EvolutionDemo.V2.Creature>()
|
|
||||||
.orderBy(.descending(\.dnaCode))
|
|
||||||
),
|
|
||||||
dataStack: dataStack
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func count(in transaction: BaseDataTransaction) throws -> Int {
|
|
||||||
|
|
||||||
return try transaction.fetchCount(
|
|
||||||
From<Advanced.EvolutionDemo.V2.Creature>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V2.Creature {
|
|
||||||
|
|
||||||
return transaction.create(
|
|
||||||
Into<Advanced.EvolutionDemo.V2.Creature>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mutate(in transaction: BaseDataTransaction) {
|
|
||||||
|
|
||||||
self.numberOfFlippers = .random(in: 1...4) * 2
|
|
||||||
self.hasVertebrae = .random()
|
|
||||||
self.hasHead = true
|
|
||||||
self.hasTail = .random()
|
|
||||||
}
|
|
||||||
}
|
|
||||||