Adds cocoapods for libraries.

Adds OCMockito and OCHamcrest libs.
This commit is contained in:
2020-09-05 22:06:51 -07:00
parent af47156557
commit c3031fbc39
364 changed files with 17147 additions and 1 deletions

View File

@@ -3,10 +3,13 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
1D2A61B332F293AB365B59E7 /* Pods_MonsterCards_MonsterCardsUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89F0D2EC2EC3C99EFD9A6949 /* Pods_MonsterCards_MonsterCardsUITests.framework */; };
92967C3D4DFE1D9C66FF994F /* Pods_MonsterCards.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA8D56491D6CAB92316D2C1B /* Pods_MonsterCards.framework */; };
CE281520762D69A9E98D19CF /* Pods_MonsterCardsTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9F017069E22ED575758F9E2 /* Pods_MonsterCardsTests.framework */; };
E20D032425031B9D00FB6E43 /* SearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032325031B9D00FB6E43 /* SearchViewController.m */; };
E20D032825031BDA00FB6E43 /* MonsterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032725031BDA00FB6E43 /* MonsterViewController.m */; };
E20D032B25031BE500FB6E43 /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032A25031BE500FB6E43 /* LibraryViewController.m */; };
@@ -54,6 +57,13 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
1A3B9A106B1FD3BB7C0750DF /* Pods-MonsterCardsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonsterCardsTests.debug.xcconfig"; path = "Target Support Files/Pods-MonsterCardsTests/Pods-MonsterCardsTests.debug.xcconfig"; sourceTree = "<group>"; };
598715810FF9D9DA2A1E91C6 /* Pods-MonsterCardsTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonsterCardsTests.release.xcconfig"; path = "Target Support Files/Pods-MonsterCardsTests/Pods-MonsterCardsTests.release.xcconfig"; sourceTree = "<group>"; };
6E60C8124CB33D697F6D0390 /* Pods-MonsterCards-MonsterCardsUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonsterCards-MonsterCardsUITests.release.xcconfig"; path = "Target Support Files/Pods-MonsterCards-MonsterCardsUITests/Pods-MonsterCards-MonsterCardsUITests.release.xcconfig"; sourceTree = "<group>"; };
89F0D2EC2EC3C99EFD9A6949 /* Pods_MonsterCards_MonsterCardsUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MonsterCards_MonsterCardsUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A7E1FCC69D4538591C4D289B /* Pods-MonsterCards.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonsterCards.debug.xcconfig"; path = "Target Support Files/Pods-MonsterCards/Pods-MonsterCards.debug.xcconfig"; sourceTree = "<group>"; };
A9F017069E22ED575758F9E2 /* Pods_MonsterCardsTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MonsterCardsTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D079B8CF0ADA838AAA0A13EA /* Pods-MonsterCards.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonsterCards.release.xcconfig"; path = "Target Support Files/Pods-MonsterCards/Pods-MonsterCards.release.xcconfig"; sourceTree = "<group>"; };
E20D032225031B9D00FB6E43 /* SearchViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SearchViewController.h; sourceTree = "<group>"; };
E20D032325031B9D00FB6E43 /* SearchViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SearchViewController.m; sourceTree = "<group>"; };
E20D032625031BDA00FB6E43 /* MonsterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MonsterViewController.h; sourceTree = "<group>"; };
@@ -80,6 +90,7 @@
E25BD60325036CF0007B04EF /* Ability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Ability.m; sourceTree = "<group>"; };
E25BD60525036CFA007B04EF /* Action.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Action.h; sourceTree = "<group>"; };
E25BD60625036CFA007B04EF /* Action.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Action.m; sourceTree = "<group>"; };
E265EE24B2C8E81E1B559306 /* Pods-MonsterCards-MonsterCardsUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonsterCards-MonsterCardsUITests.debug.xcconfig"; path = "Target Support Files/Pods-MonsterCards-MonsterCardsUITests/Pods-MonsterCards-MonsterCardsUITests.debug.xcconfig"; sourceTree = "<group>"; };
E2F7247025005E89007D87ED /* Monster Cards.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Monster Cards.app"; sourceTree = BUILT_PRODUCTS_DIR; };
E2F7247325005E89007D87ED /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
E2F7247425005E89007D87ED /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -102,6 +113,7 @@
E2FD91E72504832A00D5E935 /* DamageTypeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DamageTypeTests.m; sourceTree = "<group>"; };
E2FD91E9250493C000D5E935 /* LanguageTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LanguageTests.m; sourceTree = "<group>"; };
E2FD91EB250496B000D5E935 /* SavingThrowTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SavingThrowTests.m; sourceTree = "<group>"; };
FA8D56491D6CAB92316D2C1B /* Pods_MonsterCards.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MonsterCards.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -109,6 +121,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
92967C3D4DFE1D9C66FF994F /* Pods_MonsterCards.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -116,6 +129,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CE281520762D69A9E98D19CF /* Pods_MonsterCardsTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -123,12 +137,36 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1D2A61B332F293AB365B59E7 /* Pods_MonsterCards_MonsterCardsUITests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
609B2034EDEFF32DFBB7EA4C /* Frameworks */ = {
isa = PBXGroup;
children = (
FA8D56491D6CAB92316D2C1B /* Pods_MonsterCards.framework */,
89F0D2EC2EC3C99EFD9A6949 /* Pods_MonsterCards_MonsterCardsUITests.framework */,
A9F017069E22ED575758F9E2 /* Pods_MonsterCardsTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
6A84BC38693A798A444629A6 /* Pods */ = {
isa = PBXGroup;
children = (
A7E1FCC69D4538591C4D289B /* Pods-MonsterCards.debug.xcconfig */,
D079B8CF0ADA838AAA0A13EA /* Pods-MonsterCards.release.xcconfig */,
E265EE24B2C8E81E1B559306 /* Pods-MonsterCards-MonsterCardsUITests.debug.xcconfig */,
6E60C8124CB33D697F6D0390 /* Pods-MonsterCards-MonsterCardsUITests.release.xcconfig */,
1A3B9A106B1FD3BB7C0750DF /* Pods-MonsterCardsTests.debug.xcconfig */,
598715810FF9D9DA2A1E91C6 /* Pods-MonsterCardsTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
E20D032525031BA700FB6E43 /* Views */ = {
isa = PBXGroup;
children = (
@@ -183,6 +221,8 @@
E2F7249425005E8A007D87ED /* MonsterCardsTests */,
E2F7249F25005E8A007D87ED /* MonsterCardsUITests */,
E2F7247125005E89007D87ED /* Products */,
6A84BC38693A798A444629A6 /* Pods */,
609B2034EDEFF32DFBB7EA4C /* Frameworks */,
);
sourceTree = "<group>";
};
@@ -254,6 +294,7 @@
isa = PBXNativeTarget;
buildConfigurationList = E2F724A525005E8A007D87ED /* Build configuration list for PBXNativeTarget "MonsterCards" */;
buildPhases = (
AF1B6FE4523297C87023B0DF /* [CP] Check Pods Manifest.lock */,
E2F7246C25005E89007D87ED /* Sources */,
E2F7246D25005E89007D87ED /* Frameworks */,
E2F7246E25005E89007D87ED /* Resources */,
@@ -271,9 +312,11 @@
isa = PBXNativeTarget;
buildConfigurationList = E2F724A825005E8A007D87ED /* Build configuration list for PBXNativeTarget "MonsterCardsTests" */;
buildPhases = (
D9D7576D397FF8A326CDF668 /* [CP] Check Pods Manifest.lock */,
E2F7248D25005E8A007D87ED /* Sources */,
E2F7248E25005E8A007D87ED /* Frameworks */,
E2F7248F25005E8A007D87ED /* Resources */,
B173B419A3492DBA8FAF736D /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -289,9 +332,11 @@
isa = PBXNativeTarget;
buildConfigurationList = E2F724AB25005E8A007D87ED /* Build configuration list for PBXNativeTarget "MonsterCardsUITests" */;
buildPhases = (
5A9D2F6B7303F47844E1DAB9 /* [CP] Check Pods Manifest.lock */,
E2F7249825005E8A007D87ED /* Sources */,
E2F7249925005E8A007D87ED /* Frameworks */,
E2F7249A25005E8A007D87ED /* Resources */,
A89C1C3958588F1AC6C1F437 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -372,6 +417,109 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
5A9D2F6B7303F47844E1DAB9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-MonsterCards-MonsterCardsUITests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
A89C1C3958588F1AC6C1F437 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MonsterCards-MonsterCardsUITests/Pods-MonsterCards-MonsterCardsUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MonsterCards-MonsterCardsUITests/Pods-MonsterCards-MonsterCardsUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MonsterCards-MonsterCardsUITests/Pods-MonsterCards-MonsterCardsUITests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
AF1B6FE4523297C87023B0DF /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-MonsterCards-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
B173B419A3492DBA8FAF736D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MonsterCardsTests/Pods-MonsterCardsTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MonsterCardsTests/Pods-MonsterCardsTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MonsterCardsTests/Pods-MonsterCardsTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
D9D7576D397FF8A326CDF668 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-MonsterCardsTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
E2F7246C25005E89007D87ED /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -565,6 +713,7 @@
};
E2F724A625005E8A007D87ED /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A7E1FCC69D4538591C4D289B /* Pods-MonsterCards.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
@@ -582,6 +731,7 @@
};
E2F724A725005E8A007D87ED /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D079B8CF0ADA838AAA0A13EA /* Pods-MonsterCards.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
@@ -599,6 +749,7 @@
};
E2F724A925005E8A007D87ED /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1A3B9A106B1FD3BB7C0750DF /* Pods-MonsterCardsTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -619,6 +770,7 @@
};
E2F724AA25005E8A007D87ED /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 598715810FF9D9DA2A1E91C6 /* Pods-MonsterCardsTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -639,6 +791,7 @@
};
E2F724AC25005E8A007D87ED /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E265EE24B2C8E81E1B559306 /* Pods-MonsterCards-MonsterCardsUITests.debug.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = J793L9LQJ2;
@@ -657,6 +810,7 @@
};
E2F724AD25005E8A007D87ED /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6E60C8124CB33D697F6D0390 /* Pods-MonsterCards-MonsterCardsUITests.release.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = J793L9LQJ2;

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:MonsterCards.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?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>

23
iOS/Podfile Normal file
View File

@@ -0,0 +1,23 @@
# Uncomment the next line to define a global platform for your project
platform :ios, '13.0'
target 'MonsterCards' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for MonsterCards
target 'MonsterCardsTests' do
inherit! :search_paths
# Pods for testing
use_frameworks!
pod 'OCMockito', '~> 5.0'
end
target 'MonsterCardsUITests' do
# Pods for testing
use_frameworks!
pod 'OCMockito', '~> 5.0'
end
end

20
iOS/Podfile.lock Normal file
View File

@@ -0,0 +1,20 @@
PODS:
- OCHamcrest (7.1.2)
- OCMockito (5.1.3):
- OCHamcrest (~> 7.0)
DEPENDENCIES:
- OCMockito (~> 5.0)
SPEC REPOS:
trunk:
- OCHamcrest
- OCMockito
SPEC CHECKSUMS:
OCHamcrest: b284c9592c28c1e4025a8542e67ea41a635d0d73
OCMockito: 677cbb4a18fd492b5a4fb10144dada4de5ddb877
PODFILE CHECKSUM: eb23b43ec595daf087b654b091459c1355772a1d
COCOAPODS: 1.9.3

20
iOS/Pods/Manifest.lock generated Normal file
View File

@@ -0,0 +1,20 @@
PODS:
- OCHamcrest (7.1.2)
- OCMockito (5.1.3):
- OCHamcrest (~> 7.0)
DEPENDENCIES:
- OCMockito (~> 5.0)
SPEC REPOS:
trunk:
- OCHamcrest
- OCMockito
SPEC CHECKSUMS:
OCHamcrest: b284c9592c28c1e4025a8542e67ea41a635d0d73
OCMockito: 677cbb4a18fd492b5a4fb10144dada4de5ddb877
PODFILE CHECKSUM: eb23b43ec595daf087b654b091459c1355772a1d
COCOAPODS: 1.9.3

13
iOS/Pods/OCHamcrest/LICENSE.txt generated Normal file
View File

@@ -0,0 +1,13 @@
OCHamcrest by Jon Reid, https://qualitycoding.org/
Copyright 2019 hamcrest.org
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of Hamcrest nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
(BSD License)

244
iOS/Pods/OCHamcrest/README.md generated Normal file
View File

@@ -0,0 +1,244 @@
![ochamcrest](http://hamcrest.org/images/logo.jpg)
What is OCHamcrest?
-------------------
[![Build Status](https://travis-ci.org/hamcrest/OCHamcrest.svg?branch=master)](https://travis-ci.org/hamcrest/OCHamcrest)
[![Coverage Status](https://coveralls.io/repos/hamcrest/OCHamcrest/badge.svg?branch=master)](https://coveralls.io/r/hamcrest/OCHamcrest?branch=master)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Cocoapods Version](https://cocoapod-badges.herokuapp.com/v/OCHamcrest/badge.png)](https://cocoapods.org/pods/OCHamcrest)
[![Twitter Follow](https://img.shields.io/twitter/follow/qcoding.svg?style=social)](https://twitter.com/qcoding)
OCHamcrest is an Objective-C module providing:
* a library of "matcher" objects for declaring rules to check whether a given object matches those
rules.
* a framework for writing your own matchers.
Matchers are useful for a variety of purposes, such as UI validation. But they're most commonly used
for writing unit tests that are expressive and flexible.
My first OCHamcrest test
------------------------
We'll start by writing a very simple Xcode unit test, but instead of using XCTest's
`XCTAssertEqualObjects` function, we'll use OCHamcrest's `assertThat` construct and a predefined
matcher:
```obj-c
@import OCHamcrest;
@import XCTest;
@interface BiscuitTest : XCTestCase
@end
@implementation BiscuitTest
- (void)testEquals
{
Biscuit* theBiscuit = [[Biscuit alloc] initWithName:@"Ginger"];
Biscuit* myBiscuit = [[Biscuit alloc] initWithName:@"Ginger"];
assertThat(theBiscuit, equalTo(myBiscuit));
}
@end
```
The `assertThat` function is a stylized sentence for making a test assertion. In this example, the
subject of the assertion is the object `theBiscuit`, which is the first method parameter. The second
method parameter is a matcher for `Biscuit` objects, here a matcher that checks one object is equal
to another using the `-isEqual:` method. The test passes since the `Biscuit` class defines an
`-isEqual:` method.
OCHamcrest's functions are actually declared with an "HC_" package prefix (such as `HC_assertThat`
and `HC_equalTo`) to avoid name clashes. To make test writing faster and test code more legible,
optional short syntax is provided by default. For example, instead of writing `HC_assertThat`,
simply write `assertThat`.
Predefined matchers
-------------------
OCHamcrest comes with a library of useful matchers:
* Object
* `conformsTo` - match object that conforms to protocol
* `equalTo` - match equal object
* `hasDescription` - match object's `-description`
* `hasProperty` - match return value of method with given name
* `instanceOf` - match object type
* `isA` - match object type precisely, no subclasses
* `nilValue`, `notNilValue` - match `nil`, or not `nil`
* `sameInstance` - match same object
* `throwsException` - match block that throws an exception
* HCArgumentCaptor - match anything, capturing all values
* Number
* `closeTo` - match number close to a given value
* `greaterThan`, `greaterThanOrEqualTo`, `lessThan`,
`lessThanOrEqualTo` - match numeric ordering
* `isFalse` - match zero
* `isTrue` - match non-zero
* Text
* `containsSubstring` - match part of a string
* `endsWith` - match the end of a string
* `equalToIgnoringCase` - match the complete string but ignore case
* `equalToIgnoringWhitespace` - match the complete string but ignore extra
whitespace
* `startsWith` - match the beginning of a string
* `stringContainsInOrder`, `stringContainsInOrderIn` - match parts of a string, in relative order
* Logical
* `allOf`, `allOfIn` - "and" together all matchers
* `anyOf`, `anyOfIn` - "or" together all matchers
* `anything` - match anything (useful in composite matchers when you don't
care about a particular value)
* `isNot` - negate the matcher
* Collection
* `contains`, `containsIn` - exactly match the entire collection
* `containsInAnyOrder`, `containsInAnyOrderIn` - match the entire collection, but in any order
* `containsInRelativeOrder`, `containsInRelativeOrderIn` - match collection containing items in relative order
* `everyItem` - match if every item in a collection satisfies a given matcher
* `hasCount` - match number of elements against another matcher
* `hasCountOf` - match collection with given number of elements
* `hasEntries` - match dictionary with key-value pairs in a dictionary
* `hasEntriesIn` - match dictionary with key-value pairs in a list
* `hasEntry` - match dictionary containing a key-value pair
* `hasItem` - match if given item appears in the collection
* `hasItems`, `hasItemsIn` - match if all given items appear in the collection, in any order
* `hasKey` - match dictionary with a key
* `hasValue` - match dictionary with a value
* `isEmpty` - match empty collection
* `isIn` - match when object is in given collection
* `onlyContains`, `onlyContainsIn` - match if collection's items appear in given list
* Decorator
* `describedAs` - give the matcher a custom failure description
* `is` - decorator to improve readability - see "Syntactic sugar" below
The arguments for many of these matchers accept not just a matching value, but
another matcher, so matchers can be composed for greater flexibility. For
example, `only_contains(endsWith(@"."))` will match any collection where every
item is a string ending with period.
Syntactic sugar
---------------
OCHamcrest strives to make your tests as readable as possible. For example, the `is` matcher is a
wrapper that doesn't add any extra behavior to the underlying matcher. The following assertions are
all equivalent:
```obj-c
assertThat(theBiscuit, equalTo(myBiscuit));
assertThat(theBiscuit, is(equalTo(myBiscuit)));
assertThat(theBiscuit, is(myBiscuit));
```
The last form is allowed since `is` wraps non-matcher arguments with `equalTo`. Other matchers that
take matchers as arguments provide similar shortcuts, wrapping non-matcher arguments in `equalTo`.
How can I assert on an asynchronous call?
-----------------------------------------
`assertWithTimeout` will keep evaluating an expression until the matcher is satisfied or a timeout
is reached. For example,
```obj-c
assertWithTimeout(5, thatEventually(self.someString), is(@"expected"));
```
This repeatedly checks for this string to evaluate to "expected" before timing out after 5 seconds.
`thatEventually` is a convenience macro to create a block.
Writing custom matchers
-----------------------
OCHamcrest comes bundled with lots of useful matchers, but you'll probably find that you need to
create your own from time to time to fit your testing needs. See the
["Writing Custom Matchers" guide for more information](https://github.com/hamcrest/OCHamcrest/wiki/Writing-Custom-Matchers).
What about Swift?
-----------------
Try the [native Swift implementation of Hamcrest](https://github.com/nschum/SwiftHamcrest).
How do I add OCHamcrest to my project?
--------------------------------------
The Examples folder shows projects using OCHamcrest either through CocoaPods or through the prebuilt
frameworks, for iOS and macOS development.
### CocoaPods
If you want to add OCHamcrest using Cocoapods then add the following dependency to your Podfile.
Most people will want OCHamcrest in their test targets, and not include any pods from their main
targets:
```ruby
target 'MyTests' do
inherit! :search_paths
use_frameworks!
pod 'OCHamcrest', '~> 7.0'
end
```
Use the following import:
@import OCHamcrest;
### Carthage
Add the following to your Cartfile:
github "hamcrest/OCHamcrest" ~> 7.0
Then drag the the built framework from the appropriate Carthage/Build directory into your project,
but with "Copy items into destination group's folder" disabled.
### Prebuilt Frameworks
Prebuilt binaries are available on [GitHub](https://github.com/hamcrest/OCHamcrest/releases/). The
binaries are packaged as frameworks:
* __OCHamcrestIOS.framework__ for iOS development
* __OCHamcrest.framework__ for macOS development
Drag the appropriate framework into your project, specifying "Copy items into destination group's
folder". Then specify `-ObjC` in your "Other Linker Flags".
#### iOS Development:
Use the following import:
@import OCHamcrestIOS;
#### macOS Development:
Add a "Copy Files" build phase to copy OCHamcrest.framework to your Products Directory.
Use the following import:
@import OCHamcrest;
### Build Your Own
If you want to build OCHamcrest yourself, clone the repo, then
```sh
$ cd Source
$ ./MakeDistribution.sh
```

View File

@@ -0,0 +1,96 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@protocol HCMatcher;
NS_ASSUME_NONNULL_BEGIN
/*!
* @header
* Assertion macros for using matchers in testing frameworks.
* Unmet assertions are reported to the HCTestFailureReporterChain.
*/
FOUNDATION_EXPORT void HC_assertThatWithLocation(id testCase, _Nullable id actual, id <HCMatcher> matcher,
const char *fileName, int lineNumber);
#define HC_assertThat(actual, matcher) \
HC_assertThatWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThat(actual, matcher) -
* Asserts that actual value satisfies matcher.
* @param actual The object to evaluate as the actual value.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion assertThat passes the actual value to the matcher for evaluation. If the matcher is
* not satisfied, it is reported to the HCTestFailureReporterChain.
*
* Use assertThat in test case methods. It's designed to integrate with XCTest and other testing
* frameworks where individual tests are executed as methods.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThat instead.
*/
#define assertThat(actual, matcher) HC_assertThat(actual, matcher)
#endif
typedef _Nonnull id (^HCFutureValue)(void);
FOUNDATION_EXPORT void HC_assertWithTimeoutAndLocation(id testCase, NSTimeInterval timeout,
HCFutureValue actualBlock, id <HCMatcher> matcher,
const char *fileName, int lineNumber);
#define HC_assertWithTimeout(timeout, actualBlock, matcher) \
HC_assertWithTimeoutAndLocation(self, timeout, actualBlock, matcher, __FILE__, __LINE__)
#define HC_thatEventually(actual) ^{ return actual; }
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertWithTimeout(timeout, actualBlock, matcher) -
* Asserts that a value provided by a block will satisfy matcher within the specified time.
* @param timeout Maximum time to wait for passing behavior, specified in seconds.
* @param actualBlock A block providing the object to repeatedly evaluate as the actual value.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion <em>assertWithTimeout</em> polls a value provided by a block to asynchronously
* satisfy the matcher. The block is evaluated repeatedly for an actual value, which is passed to
* the matcher for evaluation. If the matcher is not satisfied within the timeout, it is reported to
* the HCTestFailureReporterChain.
*
* An easy way of providing the <em>actualBlock</em> is to use the macro <code>thatEventually</code>.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertWithTimeout instead.
*/
#define assertWithTimeout(timeout, actualBlock, matcher) HC_assertWithTimeout(timeout, actualBlock, matcher)
/*!
* @abstract thatEventually(actual) -
* Evaluates actual value at future time.
* @param actual The object to evaluate as the actual value.
* @discussion Wraps <em>actual</em> in a block so that it can be repeatedly evaluated by
* <code>assertWithTimeout</code>.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_thatEventually instead.
*/
#define thatEventually(actual) HC_thatEventually(actual)
#endif
/*!
* @abstract "Expected <matcher description>, but <mismatch description>"
* @discussion Helper function to let you describe mismatches the way <tt>assertThat</tt> does.
*/
FOUNDATION_EXPORT NSString *HCDescribeMismatch(id <HCMatcher> matcher, id actual);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,58 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCAssertThat.h"
#import "HCRunloopRunner.h"
#import "HCStringDescription.h"
#import "HCMatcher.h"
#import "HCTestFailure.h"
#import "HCTestFailureReporter.h"
#import "HCTestFailureReporterChain.h"
static void reportMismatch(id testCase, id actual, id <HCMatcher> matcher,
char const *fileName, int lineNumber)
{
HCTestFailure *failure = [[HCTestFailure alloc] initWithTestCase:testCase
fileName:[NSString stringWithUTF8String:fileName]
lineNumber:(NSUInteger)lineNumber
reason:HCDescribeMismatch(matcher, actual)];
HCTestFailureReporter *chain = [HCTestFailureReporterChain reporterChain];
[chain handleFailure:failure];
}
void HC_assertThatWithLocation(id testCase, _Nullable id actual, id <HCMatcher> matcher,
const char *fileName, int lineNumber)
{
if (![matcher matches:actual])
reportMismatch(testCase, actual, matcher, fileName, lineNumber);
}
void HC_assertWithTimeoutAndLocation(id testCase, NSTimeInterval timeout,
HCFutureValue actualBlock, id <HCMatcher> matcher,
const char *fileName, int lineNumber)
{
__block BOOL match = [matcher matches:actualBlock()];
if (!match)
{
HCRunloopRunner *runner = [[HCRunloopRunner alloc] initWithFulfillmentBlock:^{
match = [matcher matches:actualBlock()];
return match;
}];
[runner runUntilFulfilledOrTimeout:timeout];
}
if (!match)
reportMismatch(testCase, actualBlock(), matcher, fileName, lineNumber);
}
NSString *HCDescribeMismatch(id <HCMatcher> matcher, id actual)
{
HCStringDescription *description = [HCStringDescription stringDescription];
[[[description appendText:@"Expected "]
appendDescriptionOf:matcher]
appendText:@", but "];
[matcher describeMismatchOf:actual to:description];
return description.description;
}

View File

@@ -0,0 +1,29 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <OCHamcrest/HCDescription.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Base class for all HCDescription implementations.
*/
@interface HCBaseDescription : NSObject <HCDescription>
@end
/*!
* @abstract Methods that must be provided by subclasses of HCBaseDescription.
*/
@interface HCBaseDescription (SubclassResponsibility)
/*!
* @abstract Appends the specified string to the description.
*/
- (void)append:(NSString *)str;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,101 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCBaseDescription.h"
#import "HCMatcher.h"
@implementation HCBaseDescription
- (id <HCDescription>)appendText:(NSString *)text
{
[self append:text];
return self;
}
- (id <HCDescription>)appendDescriptionOf:(nullable id)value
{
if (value == nil)
[self append:@"nil"];
else if ([value conformsToProtocol:@protocol(HCSelfDescribing)])
[value describeTo:self];
else if ([value respondsToSelector:@selector(isKindOfClass:)] && [value isKindOfClass:[NSString class]])
[self toCSyntaxString:value];
else
[self appendObjectDescriptionOf:value];
return self;
}
- (id <HCDescription>)appendObjectDescriptionOf:(id)value
{
NSString *description = [value description];
NSUInteger descriptionLength = description.length;
if (descriptionLength == 0)
[self append:[NSString stringWithFormat:@"<%@: %p>", NSStringFromClass([value class]), (__bridge void *)value]];
else if ([description characterAtIndex:0] == '<'
&& [description characterAtIndex:descriptionLength - 1] == '>')
{
[self append:description];
}
else
{
[self append:@"<"];
[self append:description];
[self append:@">"];
}
return self;
}
- (id <HCDescription>)appendList:(NSArray *)values
start:(NSString *)start
separator:(NSString *)separator
end:(NSString *)end
{
BOOL separate = NO;
[self append:start];
for (id item in values)
{
if (separate)
[self append:separator];
[self appendDescriptionOf:item];
separate = YES;
}
[self append:end];
return self;
}
- (void)toCSyntaxString:(NSString *)unformatted
{
[self append:@"\""];
NSUInteger length = unformatted.length;
for (NSUInteger index = 0; index < length; ++index)
[self toCSyntax:[unformatted characterAtIndex:index]];
[self append:@"\""];
}
- (void)toCSyntax:(unichar)ch
{
switch (ch)
{
case '"':
[self append:@"\\\""];
break;
case '\n':
[self append:@"\\n"];
break;
case '\r':
[self append:@"\\r"];
break;
case '\t':
[self append:@"\\t"];
break;
default:
[self append:[NSString stringWithCharacters:&ch length:1]];
break;
}
}
@end

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <OCHamcrest/HCMatcher.h>
#define HC_ABSTRACT_METHOD [self subclassResponsibility:_cmd]
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Base class for all HCMatcher implementations.
* @discussion Simple matchers can just subclass HCBaseMatcher and implement <code>-matches:</code>
* and <code>-describeTo:</code>. But if the matching algorithm has several "no match" paths,
* consider subclassing HCDiagnosingMatcher instead.
*/
@interface HCBaseMatcher : NSObject <HCMatcher, NSCopying>
/*! @abstract Raises exception that command (a pseudo-abstract method) is not implemented. */
- (void)subclassResponsibility:(SEL)command;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,52 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCBaseMatcher.h"
#import "HCStringDescription.h"
@implementation HCBaseMatcher
- (NSString *)description
{
return [HCStringDescription stringFrom:self];
}
- (BOOL)matches:(nullable id)item
{
HC_ABSTRACT_METHOD;
return NO;
}
- (BOOL)matches:(nullable id)item describingMismatchTo:(id <HCDescription>)mismatchDescription
{
BOOL matchResult = [self matches:item];
if (!matchResult)
[self describeMismatchOf:item to:mismatchDescription];
return matchResult;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[[mismatchDescription appendText:@"was "] appendDescriptionOf:item];
}
- (void)describeTo:(id <HCDescription>)description
{
HC_ABSTRACT_METHOD;
}
- (void)subclassResponsibility:(SEL)command
{
NSString *className = NSStringFromClass([self class]);
[NSException raise:NSGenericException
format:@"-[%@ %@] not implemented", className, NSStringFromSelector(command)];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
@end

View File

@@ -0,0 +1,39 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract A description of an HCMatcher.
* @discussion An HCMatcher will describe itself to a description which can later be used for reporting.
*/
@protocol HCDescription <NSObject>
/*!
* @abstract Appends some plain text to the description.
* @return <code>self</code>, for chaining.
*/
- (id <HCDescription>)appendText:(NSString *)text;
/*!
* @abstract Appends description of specified value to description.
* @discussion If the value implements the HCSelfDescribing protocol, then it will be used.
* @return <code>self</code>, for chaining.
*/
- (id <HCDescription>)appendDescriptionOf:(nullable id)value;
/*!
* @abstract Appends a list of objects to the description.
* @return <code>self</code>, for chaining.
*/
- (id <HCDescription>)appendList:(NSArray *)values
start:(NSString *)start
separator:(NSString *)separator
end:(NSString *)end;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,19 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Base class for matchers that generate mismatch descriptions during the matching.
* @discussion Some matching algorithms have several "no match" paths. It helps to make the mismatch
* description as precise as possible, but we don't want to have to repeat the matching logic to do
* so. For such matchers, subclass HCDiagnosingMatcher and implement HCMatcher's
* <code>-matches:describingMismatchTo:</code>.
*/
@interface HCDiagnosingMatcher : HCBaseMatcher
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCDiagnosingMatcher.h"
@implementation HCDiagnosingMatcher
- (BOOL)matches:(nullable id)item
{
return [self matches:item describingMismatchTo:nil];
}
- (BOOL)matches:(nullable id)item describingMismatchTo:(id <HCDescription>)mismatchDescription
{
HC_ABSTRACT_METHOD;
return NO;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[self matches:item describingMismatchTo:mismatchDescription];
}
@end

View File

@@ -0,0 +1,47 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCSelfDescribing.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract A matcher over acceptable values.
* @discussion A matcher is able to describe itself to give feedback when it fails.
*
* HCMatcher implementations should not directly implement this protocol. Instead, extend the
* HCBaseMatcher class, which will ensure that the HCMatcher API can grow to support new features
* and remain compatible with all HCMatcher implementations.
*/
@protocol HCMatcher <HCSelfDescribing>
/*!
* @abstract Evaluates the matcher for argument item.
* @param item The object against which the matcher is evaluated.
* @return <code>YES</code> if item matches, otherwise <code>NO</code>.
*/
- (BOOL)matches:(nullable id)item;
/*!
* @abstract Evaluates the matcher for argument item.
* @param item The object against which the matcher is evaluated.
* @param mismatchDescription The description to be built or appended to if item does not match.
* @return <code>YES</code> if item matches, otherwise <code>NO</code>.
*/
- (BOOL)matches:(nullable id)item describingMismatchTo:(nullable id <HCDescription>)mismatchDescription;
/*!
* @abstract Generates a description of why the matcher has not accepted the item.
* @param item The item that the HCMatcher has rejected.
* @param mismatchDescription The description to be built or appended to.
* @discussion The description will be part of a larger description of why a matching failed, so it
* should be concise.
*
* This method assumes that <code>matches:item</code> is false, but will not check this.
*/
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,26 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <OCHamcrest/HCDescription.h> // Convenience header
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract The ability of an object to describe itself.
*/
@protocol HCSelfDescribing <NSObject>
/*!
* @abstract Generates a description of the object.
* @param description The description to be built or appended to.
* @discussion The description may be part of a description of a larger object of which this is just
* a component, so it should be worded appropriately.
*/
- (void)describeTo:(id <HCDescription>)description;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,36 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseDescription.h>
@protocol HCSelfDescribing;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract An HCDescription that is stored as a string.
*/
@interface HCStringDescription : HCBaseDescription
/*!
* @abstract Returns the description of an HCSelfDescribing object as a string.
* @param selfDescribing The object to be described.
* @return The description of the object.
*/
+ (NSString *)stringFrom:(id <HCSelfDescribing>)selfDescribing;
/*!
* @abstract Creates and returns an empty description.
*/
+ (instancetype)stringDescription;
/*!
* @abstract Initializes a newly allocated HCStringDescription that is initially empty.
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,45 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCStringDescription.h"
#import "HCSelfDescribing.h"
@interface HCStringDescription ()
@property (nonatomic, strong) NSMutableString *accumulator;
@end
@implementation HCStringDescription
+ (NSString *)stringFrom:(id <HCSelfDescribing>)selfDescribing
{
HCStringDescription *description = [HCStringDescription stringDescription];
[description appendDescriptionOf:selfDescribing];
return description.description;
}
+ (instancetype)stringDescription
{
return [[HCStringDescription alloc] init];
}
- (instancetype)init
{
self = [super init];
if (self)
_accumulator = [[NSMutableString alloc] init];
return self;
}
- (NSString *)description
{
return self.accumulator;
}
- (void)append:(NSString *)str
{
[self.accumulator appendString:str];
}
@end

View File

@@ -0,0 +1,26 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <stdarg.h>
@protocol HCMatcher;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Returns an array of values from a variable-length comma-separated list terminated
* by <code>nil</code>.
*/
FOUNDATION_EXPORT NSArray * HCCollectItems(id item, va_list args);
/*!
* @abstract Returns an array of matchers from a mixed array of items and matchers.
* @discussion Each item is wrapped in HCWrapInMatcher to transform non-matcher items into equality
* matchers.
*/
FOUNDATION_EXPORT NSArray<id <HCMatcher>> * HCWrapIntoMatchers(NSArray *items);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,43 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCCollect.h"
#import "HCWrapInMatcher.h"
/*!
* @abstract Returns an array of wrapped items from a variable-length comma-separated list
* terminated by <code>nil</code>.
* @discussion Each item is transformed by passing it to the specified <em>wrap</em> function.
*/
static NSArray * HCCollectWrappedItems(id item, va_list args, id (*wrap)(id))
{
NSMutableArray *list = [NSMutableArray arrayWithObject:wrap(item)];
id nextItem = va_arg(args, id);
while (nextItem)
{
[list addObject:wrap(nextItem)];
nextItem = va_arg(args, id);
}
return list;
}
static id passThrough(id value)
{
return value;
}
NSArray * HCCollectItems(id item, va_list args)
{
return HCCollectWrappedItems(item, args, passThrough);
}
NSArray<id <HCMatcher>> * HCWrapIntoMatchers(NSArray *items)
{
NSMutableArray<id <HCMatcher>> *matchers = [[NSMutableArray alloc] init];
for (id item in items)
[matchers addObject:HCWrapInMatcher(item)];
return matchers;
}

View File

@@ -0,0 +1,42 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Supporting class for matching a feature of an object.
* @discussion Tests whether the result of passing the specified invocation to the value satisfies
* the specified matcher.
*/
@interface HCInvocationMatcher : HCBaseMatcher
/*!
* @abstract Determines whether a mismatch will be described in short form.
* @discussion Default is long form, which describes the object, the name of the invocation, and the
* sub-matcher's mismatch diagnosis. Short form only has the sub-matcher's mismatch diagnosis.
*/
@property (nonatomic, assign) BOOL shortMismatchDescription;
/*!
* @abstract Initializes a newly allocated HCInvocationMatcher with an invocation and a matcher.
*/
- (instancetype)initWithInvocation:(NSInvocation *)anInvocation matching:(id <HCMatcher>)aMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
/*!
* @abstract Invokes stored invocation on the specified item and returns the result.
*/
- (id)invokeOn:(id)item;
/*!
* @abstract Returns string representation of the invocation's selector.
*/
- (NSString *)stringFromSelector;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,81 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCInvocationMatcher.h"
@interface HCInvocationMatcher ()
@property (nonatomic, strong) NSInvocation *invocation;
@property (nonatomic, strong) id <HCMatcher> subMatcher;
@end
@implementation HCInvocationMatcher
- (instancetype)initWithInvocation:(NSInvocation *)anInvocation matching:(id <HCMatcher>)aMatcher
{
self = [super init];
if (self)
{
_invocation = anInvocation;
_subMatcher = aMatcher;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
if ([self invocationNotSupportedForItem:item])
return NO;
return [self.subMatcher matches:[self invokeOn:item]];
}
- (BOOL)invocationNotSupportedForItem:(id)item
{
return ![item respondsToSelector:self.invocation.selector];
}
- (id)invokeOn:(id)item
{
__unsafe_unretained id result = nil;
[self.invocation invokeWithTarget:item];
[self.invocation getReturnValue:&result];
return result;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
if ([self invocationNotSupportedForItem:item])
[super describeMismatchOf:item to:mismatchDescription];
else
{
[self describeLongMismatchDescriptionOf:item to:mismatchDescription];
[self.subMatcher describeMismatchOf:[self invokeOn:item] to:mismatchDescription];
}
}
- (void)describeLongMismatchDescriptionOf:(id)item to:(id <HCDescription>)mismatchDescription
{
if (!self.shortMismatchDescription)
{
[[[[mismatchDescription appendDescriptionOf:item]
appendText:@" "]
appendText:[self stringFromSelector]]
appendText:@" "];
}
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[description appendText:@"an object with "]
appendText:[self stringFromSelector]]
appendText:@" "]
appendDescriptionOf:self.subMatcher];
}
- (NSString *)stringFromSelector
{
return NSStringFromSelector(self.invocation.selector);
}
@end

View File

@@ -0,0 +1,14 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Throws an NSException if <em>obj</em> is <code>nil</code>.
*/
FOUNDATION_EXPORT void HCRequireNonNilObject(id obj);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,15 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCRequireNonNilObject.h"
void HCRequireNonNilObject(id obj)
{
if (obj == nil)
{
@throw [NSException exceptionWithName:@"NilObject"
reason:@"Must be non-nil object"
userInfo:nil];
}
}

View File

@@ -0,0 +1,21 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Runs runloop until fulfilled, or timeout is reached.
* @discussion Based on http://bou.io/CTTRunLoopRunUntil.html
*/
@interface HCRunloopRunner : NSObject
- (instancetype)initWithFulfillmentBlock:(BOOL (^)(void))fulfillmentBlock NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
- (void)runUntilFulfilledOrTimeout:(CFTimeInterval)timeout;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,36 @@
#import "HCRunloopRunner.h"
@implementation HCRunloopRunner
{
CFRunLoopObserverRef _observer;
}
- (instancetype)initWithFulfillmentBlock:(BOOL (^)(void))fulfillmentBlock
{
self = [super init];
if (self)
{
_observer = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
if (fulfillmentBlock())
CFRunLoopStop(CFRunLoopGetCurrent());
else
CFRunLoopWakeUp(CFRunLoopGetCurrent());
});
CFRunLoopAddObserver(CFRunLoopGetCurrent(), _observer, kCFRunLoopDefaultMode);
}
return self;
}
- (void)dealloc
{
CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), _observer, kCFRunLoopDefaultMode);
CFRelease(_observer);
}
- (void)runUntilFulfilledOrTimeout:(CFTimeInterval)timeout
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, false);
}
@end

View File

@@ -0,0 +1,17 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@protocol HCMatcher;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Wraps argument in a matcher, if necessary.
* @return The argument as-is if it is already a matcher, otherwise wrapped in an <em>equalTo</em> matcher.
*/
FOUNDATION_EXPORT _Nullable id <HCMatcher> HCWrapInMatcher(_Nullable id matcherOrValue);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCWrapInMatcher.h"
#import "HCIsEqual.h"
_Nullable id <HCMatcher> HCWrapInMatcher(_Nullable id matcherOrValue)
{
if (!matcherOrValue)
return nil;
if ([matcherOrValue conformsToProtocol:@protocol(HCMatcher)])
return matcherOrValue;
return HC_equalTo(matcherOrValue);
}

View File

@@ -0,0 +1,17 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSInvocation (OCHamcrest)
+ (NSInvocation *)och_invocationWithTarget:(id)target selector:(SEL)selector;
+ (NSInvocation *)och_invocationOnObjectOfType:(Class)aClass selector:(SEL)selector;
- (id)och_invoke;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,45 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "NSInvocation+OCHamcrest.h"
#import "HCReturnValueGetter.h"
#import "HCReturnTypeHandlerChain.h"
@implementation NSInvocation (OCHamcrest)
+ (NSInvocation *)och_invocationWithTarget:(id)target selector:(SEL)selector
{
NSMethodSignature *signature = [target methodSignatureForSelector:selector];
NSInvocation *invocation= [self och_invocationWithSignature:signature selector:selector];
invocation.target = target;
return invocation;
}
+ (NSInvocation *)och_invocationOnObjectOfType:(Class)aClass selector:(SEL)selector
{
NSMethodSignature *signature = [aClass instanceMethodSignatureForSelector:selector];
return [self och_invocationWithSignature:signature selector:selector];
}
+ (NSInvocation *)och_invocationWithSignature:(NSMethodSignature *)signature selector:(SEL)selector
{
NSInvocation *invocation = [[self class] invocationWithMethodSignature:signature];
invocation.selector = selector;
return invocation;
}
- (id)och_invoke
{
[self invoke];
return [self och_returnValue];
}
- (id)och_returnValue
{
char const *returnType = self.methodSignature.methodReturnType;
return [HCReturnValueGetterChain() returnValueOfType:returnType fromInvocation:self];
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCBoolReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCBoolReturnGetter.h"
@implementation HCBoolReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(BOOL) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
BOOL value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCCharReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCCharReturnGetter.h"
@implementation HCCharReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(char) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
char value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCDoubleReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCDoubleReturnGetter.h"
@implementation HCDoubleReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(double) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
double value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCFloatReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCFloatReturnGetter.h"
@implementation HCFloatReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(float) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
float value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCIntReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIntReturnGetter.h"
@implementation HCIntReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(int) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
int value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCLongLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCLongLongReturnGetter.h"
@implementation HCLongLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(long long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
long long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCLongReturnGetter.h"
@implementation HCLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCObjectReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCObjectReturnGetter.h"
@implementation HCObjectReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(id) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
__unsafe_unretained id value;
[invocation getReturnValue:&value];
return value;
}
@end

View File

@@ -0,0 +1,12 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@class HCReturnValueGetter;
/*!
* @abstract Returns chain of return type handlers.
*/
FOUNDATION_EXPORT HCReturnValueGetter *HCReturnValueGetterChain(void);

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnTypeHandlerChain.h"
#import "HCObjectReturnGetter.h"
#import "HCCharReturnGetter.h"
#import "HCBoolReturnGetter.h"
#import "HCIntReturnGetter.h"
#import "HCShortReturnGetter.h"
#import "HCLongReturnGetter.h"
#import "HCLongLongReturnGetter.h"
#import "HCUnsignedCharReturnGetter.h"
#import "HCUnsignedIntReturnGetter.h"
#import "HCUnsignedShortReturnGetter.h"
#import "HCUnsignedLongReturnGetter.h"
#import "HCUnsignedLongLongReturnGetter.h"
#import "HCFloatReturnGetter.h"
#import "HCDoubleReturnGetter.h"
HCReturnValueGetter *HCReturnValueGetterChain(void)
{
static HCReturnValueGetter *chain = nil;
if (!chain)
{
HCReturnValueGetter *doubleHandler = [[HCDoubleReturnGetter alloc] initWithSuccessor:nil];
HCReturnValueGetter *floatHandler = [[HCFloatReturnGetter alloc] initWithSuccessor:doubleHandler];
HCReturnValueGetter *uLongLongHandler = [[HCUnsignedLongLongReturnGetter alloc] initWithSuccessor:floatHandler];
HCReturnValueGetter *uLongHandler = [[HCUnsignedLongReturnGetter alloc] initWithSuccessor:uLongLongHandler];
HCReturnValueGetter *uShortHandler = [[HCUnsignedShortReturnGetter alloc] initWithSuccessor:uLongHandler];
HCReturnValueGetter *uIntHandler = [[HCUnsignedIntReturnGetter alloc] initWithSuccessor:uShortHandler];
HCReturnValueGetter *uCharHandler = [[HCUnsignedCharReturnGetter alloc] initWithSuccessor:uIntHandler];
HCReturnValueGetter *longLongHandler = [[HCLongLongReturnGetter alloc] initWithSuccessor:uCharHandler];
HCReturnValueGetter *longHandler = [[HCLongReturnGetter alloc] initWithSuccessor:longLongHandler];
HCReturnValueGetter *shortHandler = [[HCShortReturnGetter alloc] initWithSuccessor:longHandler];
HCReturnValueGetter *intHandler = [[HCIntReturnGetter alloc] initWithSuccessor:shortHandler];
HCReturnValueGetter *boolHandler = [[HCBoolReturnGetter alloc] initWithSuccessor:intHandler];
HCReturnValueGetter *charHandler = [[HCCharReturnGetter alloc] initWithSuccessor:boolHandler];
HCReturnValueGetter *objectHandler = [[HCObjectReturnGetter alloc] initWithSuccessor:charHandler];
chain = objectHandler;
}
return chain;
}

View File

@@ -0,0 +1,20 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Chain-of-responsibility for handling NSInvocation return types.
*/
@interface HCReturnValueGetter : NSObject
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
- (id)returnValueOfType:(char const *)type fromInvocation:(NSInvocation *)invocation;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,42 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
@interface HCReturnValueGetter (SubclassResponsibility)
- (id)returnValueFromInvocation:(NSInvocation *)invocation;
@end
@interface HCReturnValueGetter ()
@property (nonatomic, assign, readonly) char const *handlerType;
@property (nullable, nonatomic, strong, readonly) HCReturnValueGetter *successor;
@end
@implementation HCReturnValueGetter
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor
{
self = [super init];
if (self)
{
_handlerType = handlerType;
_successor = successor;
}
return self;
}
- (BOOL)handlesReturnType:(char const *)returnType
{
return strcmp(returnType, self.handlerType) == 0;
}
- (id)returnValueOfType:(char const *)type fromInvocation:(NSInvocation *)invocation
{
if ([self handlesReturnType:type])
return [self returnValueFromInvocation:invocation];
return [self.successor returnValueOfType:type fromInvocation:invocation];
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCShortReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCShortReturnGetter.h"
@implementation HCShortReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(short) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
short value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedCharReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedCharReturnGetter.h"
@implementation HCUnsignedCharReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned char) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned char value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedIntReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedIntReturnGetter.h"
@implementation HCUnsignedIntReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned int) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned int value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedLongLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedLongLongReturnGetter.h"
@implementation HCUnsignedLongLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned long long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned long long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedLongReturnGetter.h"
@implementation HCUnsignedLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedShortReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedShortReturnGetter.h"
@implementation HCUnsignedShortReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned short) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned short value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,8 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCGenericTestFailureReporter : HCTestFailureReporter
@end

View File

@@ -0,0 +1,31 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCGenericTestFailureReporter.h"
#import "HCTestFailure.h"
@implementation HCGenericTestFailureReporter
- (BOOL)willHandleFailure:(HCTestFailure *)failure
{
return YES;
}
- (void)executeHandlingOfFailure:(HCTestFailure *)failure
{
NSException *exception = [self createExceptionForFailure:failure];
[exception raise];
}
- (NSException *)createExceptionForFailure:(HCTestFailure *)failure
{
NSString *failureReason = [NSString stringWithFormat:@"%@:%lu: matcher error: %@",
failure.fileName,
(unsigned long)failure.lineNumber,
failure.reason];
return [NSException exceptionWithName:@"HCGenericTestFailure" reason:failureReason userInfo:nil];
}
@end

View File

@@ -0,0 +1,8 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCSenTestFailureReporter : HCTestFailureReporter
@end

View File

@@ -0,0 +1,69 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCSenTestFailureReporter.h"
#import "HCTestFailure.h"
#import "NSInvocation+OCHamcrest.h"
@interface NSObject (PretendMethodsExistOnNSObjectToAvoidLinkingSenTestingKit)
+ (NSException *)failureInFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
- (void)failWithException:(NSException *)exception;
@end
@interface NSInvocation (OCHamcrest_SenTestingKit)
@end
@implementation NSInvocation (OCHamcrest_SenTestingKit)
+ (NSInvocation *)och_SenTestFailureInFile:(NSString *)fileName
atLine:(NSUInteger)lineNumber
description:(NSString *)description
{
// SenTestingKit expects a format string, but NSInvocation does not support varargs.
// Mask % symbols in the string so they aren't treated as placeholders.
NSString *massagedDescription = [description stringByReplacingOccurrencesOfString:@"%"
withString:@"%%"];
NSInvocation *invocation = [NSInvocation och_invocationWithTarget:[NSException class]
selector:@selector(failureInFile:atLine:withDescription:)];
[invocation setArgument:&fileName atIndex:2];
[invocation setArgument:&lineNumber atIndex:3];
[invocation setArgument:&massagedDescription atIndex:4];
return invocation;
}
@end
@implementation HCSenTestFailureReporter
- (BOOL)willHandleFailure:(HCTestFailure *)failure
{
return [failure.testCase respondsToSelector:@selector(failWithException:)];
}
- (void)executeHandlingOfFailure:(HCTestFailure *)failure
{
NSException *exception = [self createExceptionForFailure:failure];
[failure.testCase failWithException:exception];
}
- (NSException *)createExceptionForFailure:(HCTestFailure *)failure
{
NSInvocation *invocation = [NSInvocation och_SenTestFailureInFile:failure.fileName
atLine:failure.lineNumber
description:failure.reason];
[invocation invoke];
__unsafe_unretained NSException *result = nil;
[invocation getReturnValue:&result];
return result;
}
@end

View File

@@ -0,0 +1,42 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
@abstract Test failure location and reason.
*/
@interface HCTestFailure : NSObject
/*!
* @abstract Test case used to run test method.
* @discussion Can be <code>nil</code>.
*
* For unmet OCHamcrest assertions, if the assertion was <code>assertThat</code> or
* <code>assertWithTimeout</code>, <em>testCase</em> will be the test case instance.
*/
@property (nonatomic, strong, readonly) id testCase;
/*! @abstract File name to report. */
@property (nonatomic, copy, readonly) NSString *fileName;
/*! @abstract Line number to report. */
@property (nonatomic, assign, readonly) NSUInteger lineNumber;
/*! @abstract Failure reason to report. */
@property (nonatomic, strong, readonly) NSString *reason;
/*!
* @abstract Initializes a newly allocated instance of a test failure.
*/
- (instancetype)initWithTestCase:(id)testCase
fileName:(NSString *)fileName
lineNumber:(NSUInteger)lineNumber
reason:(NSString *)reason;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailure.h"
@implementation HCTestFailure
- (instancetype)initWithTestCase:(id)testCase
fileName:(NSString *)fileName
lineNumber:(NSUInteger)lineNumber
reason:(NSString *)reason
{
self = [super init];
if (self)
{
_testCase = testCase;
_fileName = [fileName copy];
_lineNumber = lineNumber;
_reason = [reason copy];
}
return self;
}
@end

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@class HCTestFailure;
NS_ASSUME_NONNULL_BEGIN
/*!
Chain-of-responsibility for handling test failures.
*/
@interface HCTestFailureReporter : NSObject
@property (nullable, nonatomic, strong) HCTestFailureReporter *successor;
/*!
Handle test failure at specific location, or pass to successor.
*/
- (void)handleFailure:(HCTestFailure *)failure;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCTestFailureReporter (SubclassResponsibility)
- (BOOL)willHandleFailure:(HCTestFailure *)failure;
- (void)executeHandlingOfFailure:(HCTestFailure *)failure;
@end
@implementation HCTestFailureReporter
- (void)handleFailure:(HCTestFailure *)failure
{
if ([self willHandleFailure:failure])
[self executeHandlingOfFailure:failure];
else
[self.successor handleFailure:failure];
}
@end

View File

@@ -0,0 +1,36 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@class HCTestFailureReporter;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Manage chain-of-responsibility for reporting test failures.
* @discussion This provides a generic way of reporting test failures without knowing about the
* underlying test framework. By default, we try XCTest first, then SenTestingKit. If we run out of
* options, the final catch-all is to throw an NSException describing the test failure.
*/
@interface HCTestFailureReporterChain : NSObject
/*!
* @abstract Returns current chain of test failure reporters.
*/
+ (HCTestFailureReporter *)reporterChain;
/*!
* @abstract Adds specified test failure reporter to head of chain-of-responsibility.
*/
+ (void)addReporter:(HCTestFailureReporter *)reporter;
/*!
* @abstract Resets chain-of-responsibility to default.
*/
+ (void)reset;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,41 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporterChain.h"
#import "HCGenericTestFailureReporter.h"
#import "HCSenTestFailureReporter.h"
#import "HCXCTestFailureReporter.h"
static HCTestFailureReporter *chainHead = nil;
@implementation HCTestFailureReporterChain
+ (HCTestFailureReporter *)reporterChain
{
if (!chainHead)
{
HCTestFailureReporter *xctestReporter = [[HCXCTestFailureReporter alloc] init];
HCTestFailureReporter *ocunitReporter = [[HCSenTestFailureReporter alloc] init];
HCTestFailureReporter *genericReporter = [[HCGenericTestFailureReporter alloc] init];
chainHead = xctestReporter;
xctestReporter.successor = ocunitReporter;
ocunitReporter.successor = genericReporter;
}
return chainHead;
}
+ (void)addReporter:(HCTestFailureReporter *)reporter
{
reporter.successor = [self reporterChain];
chainHead = reporter;
}
+ (void)reset
{
chainHead = nil;
}
@end

View File

@@ -0,0 +1,8 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCXCTestFailureReporter : HCTestFailureReporter
@end

View File

@@ -0,0 +1,33 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCXCTestFailureReporter.h"
#import "HCTestFailure.h"
@interface NSObject (PretendMethodExistsOnNSObjectToAvoidLinkingXCTest)
- (void)recordFailureWithDescription:(NSString *)description
inFile:(NSString *)filename
atLine:(NSUInteger)lineNumber
expected:(BOOL)expected;
@end
@implementation HCXCTestFailureReporter
- (BOOL)willHandleFailure:(HCTestFailure *)failure
{
return [failure.testCase respondsToSelector:@selector(recordFailureWithDescription:inFile:atLine:expected:)];
}
- (void)executeHandlingOfFailure:(HCTestFailure *)failure
{
[failure.testCase recordFailureWithDescription:failure.reason
inFile:failure.fileName
atLine:failure.lineNumber
expected:YES];
}
@end

View File

@@ -0,0 +1,45 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies a nested matcher.
*/
@interface HCEvery : HCDiagnosingMatcher
@property (nonatomic, strong, readonly) id <HCMatcher> matcher;
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_everyItem(id <HCMatcher> itemMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when the examined collection's items are
* all matched by the specified matcher.
* @param itemMatcher The matcher to apply to every item provided by the examined collection.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"bar", \@"baz"], everyItem(startsWith(\@"ba")))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_everyItem instead.
*/
static inline id everyItem(id <HCMatcher> itemMatcher)
{
return HC_everyItem(itemMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,74 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCEvery.h"
#import "HCRequireNonNilObject.h"
@implementation HCEvery
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher
{
HCRequireNonNilObject(matcher);
self = [super init];
if (self)
_matcher = matcher;
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
if ([collection count] == 0)
{
[mismatchDescription appendText:@"was empty"];
return NO;
}
for (id item in collection)
{
if (![self.matcher matches:item])
{
[self describeAllMismatchesInCollection:collection to:mismatchDescription];
return NO;
}
}
return YES;
}
- (void)describeAllMismatchesInCollection:(id)collection to:(id <HCDescription>)mismatchDescription
{
[mismatchDescription appendText:@"mismatches were: ["];
BOOL isPastFirst = NO;
for (id item in collection)
{
if (![self.matcher matches:item])
{
if (isPastFirst)
[mismatchDescription appendText:@", "];
[self.matcher describeMismatchOf:item to:mismatchDescription];
isPastFirst = YES;
}
}
[mismatchDescription appendText:@"]"];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"every item is "] appendDescriptionOf:self.matcher];
}
@end
id HC_everyItem(id <HCMatcher> itemMatcher)
{
return [[HCEvery alloc] initWithMatcher:itemMatcher];
}

View File

@@ -0,0 +1,63 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if collection size satisfies a nested matcher.
*/
@interface HCHasCount : HCBaseMatcher
- (instancetype)initWithMatcher:(id <HCMatcher>)countMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasCount(id <HCMatcher> countMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object's <code>-count</code> method
* returns a value that satisfies the specified matcher.
* @param countMatcher A matcher for the count of an examined collection.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], hasCount(equalTo(@2)))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasCount instead.
*/
static inline id hasCount(id <HCMatcher> countMatcher)
{
return HC_hasCount(countMatcher);
}
#endif
FOUNDATION_EXPORT id HC_hasCountOf(NSUInteger count);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object's <code>-count</code> method
* returns a value that equals the specified value.
* @param value Value to compare against as the expected count.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], hasCountOf(2))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasCountOf instead.
*/
static inline id hasCountOf(NSUInteger value)
{
return HC_hasCountOf(value);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,65 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCHasCount.h"
#import "HCIsEqual.h"
@interface HCHasCount ()
@property (nonatomic, strong, readonly) id <HCMatcher> countMatcher;
@end
@implementation HCHasCount
- (instancetype)initWithMatcher:(id <HCMatcher>)countMatcher
{
self = [super init];
if (self)
_countMatcher = countMatcher;
return self;
}
- (BOOL)matches:(nullable id)item
{
if (![self itemHasCount:item])
return NO;
NSNumber *count = @([item count]);
return [self.countMatcher matches:count];
}
- (BOOL)itemHasCount:(id)item
{
return [item respondsToSelector:@selector(count)];
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[mismatchDescription appendText:@"was "];
if ([self itemHasCount:item])
{
[[[mismatchDescription appendText:@"count of "]
appendDescriptionOf:@([item count])]
appendText:@" with "];
}
[mismatchDescription appendDescriptionOf:item];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection with count of "] appendDescriptionOf:self.countMatcher];
}
@end
id HC_hasCount(id <HCMatcher> countMatcher)
{
return [[HCHasCount alloc] initWithMatcher:countMatcher];
}
id HC_hasCountOf(NSUInteger value)
{
return HC_hasCount(HC_equalTo(@(value)));
}

View File

@@ -0,0 +1,95 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any item in a collection satisfies a nested matcher.
*/
@interface HCIsCollectionContaining : HCDiagnosingMatcher
- (instancetype)initWithMatcher:(id <HCMatcher>)elementMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasItem(id itemMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract hasItem(itemMatcher) -
* Creates a matcher for collections that matches when at least one item in the examined collection
* satisfies the specified matcher.
* @param itemMatcher The matcher to apply to collection elements, or an expected value
* for <em>equalTo</em> matching.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass.
*
* If <em>itemMatcher</em> is not a matcher, it is implicitly wrapped in an <em>equalTo</em> matcher
* to check for equality.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@1, \@2, \@3], hasItem(equalTo(\@2)))</pre>
*
* <pre>assertThat(\@[\@1, \@2, \@3], hasItem(\@2))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasItem instead.
*/
#define hasItem HC_hasItem
#endif
FOUNDATION_EXPORT id HC_hasItemsIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when all specified matchers are
* satisfied by any item in the examined collection.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing one pass for each matcher.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar", \@"baz"], hasItems(\@[endsWith(\@"z"), endsWith(\@"o")]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasItemsIn instead.
*/
static inline id hasItemsIn(NSArray *itemMatchers)
{
return HC_hasItemsIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_hasItems(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when all specified matchers are
* satisfied by any item in the examined collection.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing one pass for each matcher.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar", \@"baz"], hasItems(endsWith(\@"z"), endsWith(\@"o"), nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasItems instead.
*/
#define hasItems(itemMatchers...) HC_hasItems(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,88 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContaining.h"
#import "HCAllOf.h"
#import "HCCollect.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsCollectionContaining ()
@property (nonatomic, strong, readonly) id <HCMatcher> elementMatcher;
@end
@implementation HCIsCollectionContaining
- (instancetype)initWithMatcher:(id <HCMatcher>)elementMatcher
{
self = [super init];
if (self)
_elementMatcher = elementMatcher;
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
if ([collection count] == 0)
{
[mismatchDescription appendText:@"was empty"];
return NO;
}
for (id item in collection)
if ([self.elementMatcher matches:item])
return YES;
[mismatchDescription appendText:@"mismatches were: ["];
BOOL isPastFirst = NO;
for (id item in collection)
{
if (isPastFirst)
[mismatchDescription appendText:@", "];
[self.elementMatcher describeMismatchOf:item to:mismatchDescription];
isPastFirst = YES;
}
[mismatchDescription appendText:@"]"];
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection containing "]
appendDescriptionOf:self.elementMatcher];
}
@end
id HC_hasItem(id itemMatcher)
{
HCRequireNonNilObject(itemMatcher);
return [[HCIsCollectionContaining alloc] initWithMatcher:HCWrapInMatcher(itemMatcher)];
}
id HC_hasItemsIn(NSArray *itemMatchers)
{
NSMutableArray *matchers = [[NSMutableArray alloc] init];
for (id itemMatcher in itemMatchers)
[matchers addObject:HC_hasItem(itemMatcher)];
return HC_allOfIn(matchers);
}
id HC_hasItems(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_hasItemsIn(array);
}

View File

@@ -0,0 +1,79 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection, in any order, satisfy a list of nested matchers.
*/
@interface HCIsCollectionContainingInAnyOrder : HCDiagnosingMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_containsInAnyOrderIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates an order-agnostic matcher for collections that matches when each item in the
* examined collection satisfies one matcher anywhere in the specified list of matchers.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* Note: Each matcher in the specified list will only be used once during a given examination, so
* be careful when specifying matchers that may be satisfied by more than one entry in an examined
* collection.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrderIn(\@[equalTo(\@"bar"), equalTo(\@"foo")]))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrderIn(@[\@"bar", \@"foo"]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsInAnyOrderIn instead.
*/
static inline id containsInAnyOrderIn(NSArray *itemMatchers)
{
return HC_containsInAnyOrderIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_containsInAnyOrder(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates an order-agnostic matcher for collections that matches when each item in the
* examined collection satisfies one matcher anywhere in the specified list of matchers.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* Note: Each matcher in the specified list will only be used once during a given examination, so
* be careful when specifying matchers that may be satisfied by more than one entry in an examined
* collection.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrder(equalTo(\@"bar"), equalTo(\@"foo"), nil))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrder(\@"bar", \@"foo", nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsInAnyOrder instead.
*/
#define containsInAnyOrder(itemMatchers...) HC_containsInAnyOrder(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,115 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContainingInAnyOrder.h"
#import "HCCollect.h"
@interface HCMatchingInAnyOrder : NSObject
@property (nonatomic, copy, readonly) NSMutableArray<id <HCMatcher>> *matchers;
@property (nonatomic, strong, readonly) id <HCDescription> mismatchDescription;
@end
@implementation HCMatchingInAnyOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
mismatchDescription:(id <HCDescription>)description
{
self = [super init];
if (self)
{
_matchers = [itemMatchers mutableCopy];
_mismatchDescription = description;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
NSUInteger index = 0;
for (id <HCMatcher> matcher in self.matchers)
{
if ([matcher matches:item])
{
[self.matchers removeObjectAtIndex:index];
return YES;
}
++index;
}
[[self.mismatchDescription appendText:@"not matched: "]
appendDescriptionOf:item];
return NO;
}
- (BOOL)isFinishedWith:(NSArray *)collection
{
if (self.matchers.count == 0)
return YES;
[[[[self.mismatchDescription appendText:@"no item matches: "]
appendList:self.matchers start:@"" separator:@", " end:@""]
appendText:@" in "]
appendList:collection start:@"[" separator:@", " end:@"]"];
return NO;
}
@end
@interface HCIsCollectionContainingInAnyOrder ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCIsCollectionContainingInAnyOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
{
self = [super init];
if (self)
_matchers = [itemMatchers copy];
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
HCMatchingInAnyOrder *matchSequence =
[[HCMatchingInAnyOrder alloc] initWithMatchers:self.matchers
mismatchDescription:mismatchDescription];
for (id item in collection)
if (![matchSequence matches:item])
return NO;
return [matchSequence isFinishedWith:collection];
}
- (void)describeTo:(id <HCDescription>)description
{
[[[description appendText:@"a collection over "]
appendList:self.matchers start:@"[" separator:@", " end:@"]"]
appendText:@" in any order"];
}
@end
id HC_containsInAnyOrderIn(NSArray *itemMatchers)
{
return [[HCIsCollectionContainingInAnyOrder alloc] initWithMatchers:HCWrapIntoMatchers(itemMatchers)];
}
id HC_containsInAnyOrder(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_containsInAnyOrderIn(array);
}

View File

@@ -0,0 +1,71 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies a list of nested matchers, in order.
*/
@interface HCIsCollectionContainingInOrder : HCDiagnosingMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_containsIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item in the examined
* collection satisfies the corresponding matcher in the specified list of matchers.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], containsIn(\@[equalTo(\@"foo"), equalTo(\@"bar")]))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], containsIn(\@[\@"foo", \@"bar"]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsIn instead.)
*/
static inline id containsIn(NSArray *itemMatchers)
{
return HC_containsIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_contains(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item in the examined
* collection satisfies the corresponding matcher in the specified list of matchers.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], contains(equalTo(\@"foo"), equalTo(\@"bar"), nil))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], contains(\@"foo", \@"bar", nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_contains instead.)
*/
#define contains(itemMatchers...) HC_contains(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,134 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContainingInOrder.h"
#import "HCCollect.h"
@interface HCMatchSequence : NSObject
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@property (nonatomic, strong, readonly) id <HCDescription> mismatchDescription;
@property (nonatomic, assign) NSUInteger nextMatchIndex;
@end
@implementation HCMatchSequence
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
mismatchDescription:(id <HCDescription>)description
{
self = [super init];
if (self)
{
_matchers = [itemMatchers copy];
_mismatchDescription = description;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
return [self isNotSurplus:item] && [self isMatched:item];
}
- (BOOL)isFinished
{
if (self.nextMatchIndex < self.matchers.count)
{
[[self.mismatchDescription appendText:@"no item was "]
appendDescriptionOf:self.matchers[self.nextMatchIndex]];
return NO;
}
return YES;
}
- (BOOL)isMatched:(id)item
{
id <HCMatcher> matcher = self.matchers[self.nextMatchIndex];
if (![matcher matches:item])
{
[self describeMismatchOfMatcher:matcher item:item];
return NO;
}
++self.nextMatchIndex;
return YES;
}
- (BOOL)isNotSurplus:(id)item
{
if (self.matchers.count <= self.nextMatchIndex)
{
[[self.mismatchDescription
appendText:[NSString stringWithFormat:@"exceeded count of %lu with item ",
(unsigned long)self.matchers.count]]
appendDescriptionOf:item];
return NO;
}
return YES;
}
- (void)describeMismatchOfMatcher:(id <HCMatcher>)matcher item:(id)item
{
[self.mismatchDescription appendText:[NSString stringWithFormat:@"item %lu: ",
(unsigned long)self.nextMatchIndex]];
[matcher describeMismatchOf:item to:self.mismatchDescription];
}
@end
@interface HCIsCollectionContainingInOrder ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCIsCollectionContainingInOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
{
self = [super init];
if (self)
_matchers = [itemMatchers copy];
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
HCMatchSequence *matchSequence =
[[HCMatchSequence alloc] initWithMatchers:self.matchers
mismatchDescription:mismatchDescription];
for (id item in collection)
if (![matchSequence matches:item])
return NO;
return [matchSequence isFinished];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection containing "]
appendList:self.matchers start:@"[" separator:@", " end:@"]"];
}
@end
id HC_containsIn(NSArray *itemMatchers)
{
return [[HCIsCollectionContainingInOrder alloc] initWithMatchers:HCWrapIntoMatchers(itemMatchers)];
}
id HC_contains(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_containsIn(array);
}

View File

@@ -0,0 +1,48 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies a list of nested matchers, in order.
*/
@interface HCIsCollectionContainingInRelativeOrder : HCDiagnosingMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_containsInRelativeOrder(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when the examined collection contains
* items satisfying the specified list of matchers, in the same relative order.
* @param itemMatchers Array of matchers that must be satisfied by the items provided by the
* examined collection in the same relative order.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass.
*
* Any element of <em>itemMatchers</em> that is not a matcher is implicitly wrapped in an
* <em>equalTo</em> matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@1, \@2, \@3, \@4, \@5], containsInRelativeOrder(equalTo(\@2), equalTo(\@4)))</pre>
* <pre>assertThat(\@[\@1, \@2, \@3, \@4, \@5], containsInRelativeOrder(\@2, \@4))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsInRelativeOrder instead.
*/
static inline id containsInRelativeOrder(NSArray *itemMatchers)
{
return HC_containsInRelativeOrder(itemMatchers);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,124 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContainingInRelativeOrder.h"
#import "HCCollect.h"
static void HCRequireNonEmptyArray(NSArray *array)
{
if (!array.count)
{
@throw [NSException exceptionWithName:@"EmptyArray"
reason:@"Must be non-empty array"
userInfo:nil];
}
}
@interface HCMatchSequenceInRelativeOrder : NSObject
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@property (nonatomic, strong, readonly) id <HCDescription> mismatchDescription;
@property (nonatomic, assign) NSUInteger nextMatchIndex;
@property (nonatomic, strong) id lastMatchedItem;
@end
@implementation HCMatchSequenceInRelativeOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
mismatchDescription:(id <HCDescription>)description
{
self = [super init];
if (self)
{
_matchers = [itemMatchers copy];
_mismatchDescription = description;
}
return self;
}
- (void)processItems:(NSArray *)sequence
{
for (id item in sequence)
{
if (self.nextMatchIndex < self.matchers.count)
{
id <HCMatcher> matcher = self.matchers[self.nextMatchIndex];
if ([matcher matches:item])
{
self.lastMatchedItem = item;
self.nextMatchIndex += 1;
}
}
}
}
- (BOOL)isFinished
{
if (self.nextMatchIndex < self.matchers.count)
{
[[self.mismatchDescription
appendDescriptionOf:self.matchers[self.nextMatchIndex]]
appendText:@" was not found"];
if (self.lastMatchedItem != nil)
{
[[self.mismatchDescription
appendText:@" after "]
appendDescriptionOf:self.lastMatchedItem];
}
return NO;
}
return YES;
}
@end
@interface HCIsCollectionContainingInRelativeOrder ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCIsCollectionContainingInRelativeOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
{
HCRequireNonEmptyArray(itemMatchers);
self = [super init];
if (self)
_matchers = [itemMatchers copy];
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
HCMatchSequenceInRelativeOrder *matchSequenceInRelativeOrder =
[[HCMatchSequenceInRelativeOrder alloc] initWithMatchers:self.matchers
mismatchDescription:mismatchDescription];
[matchSequenceInRelativeOrder processItems:collection];
return [matchSequenceInRelativeOrder isFinished];
}
- (void)describeTo:(id <HCDescription>)description
{
[[[description
appendText:@"a collection containing "]
appendList:self.matchers start:@"[" separator:@", " end:@"]"]
appendText:@" in relative order"];
}
@end
id HC_containsInRelativeOrder(NSArray *itemMatchers)
{
NSArray *matchers = HCWrapIntoMatchers(itemMatchers);
return [[HCIsCollectionContainingInRelativeOrder alloc] initWithMatchers:matchers];
}

View File

@@ -0,0 +1,62 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCEvery.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies any of the nested matchers.
*/
@interface HCIsCollectionOnlyContaining : HCEvery
@end
FOUNDATION_EXPORT id HC_onlyContainsIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item of the examined
* collection satisfies any of the specified matchers.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. Any matcher may match multiple elements.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"Jon", \@"John", \@"Bob"], onlyContainsIn(\@[startsWith(\@"Jo"), startsWith(\@("Bo")]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_onlyContainsIn instead.
*/
static inline id onlyContainsIn(NSArray *itemMatchers)
{
return HC_onlyContainsIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_onlyContains(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item of the examined
* collection satisfies any of the specified matchers.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check for
* equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. Any matcher may match multiple elements.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"Jon", \@"John", \@"Bob"], onlyContains(startsWith(\@"Jo"), startsWith(\@("Bo"), nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_onlyContains instead.
*/
#define onlyContains(itemMatchers...) HC_onlyContains(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,34 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionOnlyContaining.h"
#import "HCAnyOf.h"
#import "HCCollect.h"
@implementation HCIsCollectionOnlyContaining
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection containing items matching "]
appendDescriptionOf:self.matcher];
}
@end
id HC_onlyContainsIn(NSArray *itemMatchers)
{
return [[HCIsCollectionOnlyContaining alloc] initWithMatcher:HC_anyOfIn(itemMatchers)];
}
id HC_onlyContains(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_onlyContainsIn(array);
}

View File

@@ -0,0 +1,47 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any entry in a dictionary satisfies the nested pair of matchers.
*/
@interface HCIsDictionaryContaining : HCBaseMatcher
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher
valueMatcher:(id <HCMatcher>)valueMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasEntry(id keyMatcher, id valueMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* at least one entry whose key satisfies the specified <code>keyMatcher</code> <b>and</b> whose
* value satisfies the specified <code>valueMatcher</code>.
* @param keyMatcher The matcher to satisfy for the key, or an expected value for <em>equalTo</em> matching.
* @param valueMatcher The matcher to satisfy for the value, or an expected value for <em>equalTo</em> matching.
* @discussion Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em>
* matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(myDictionary, hasEntry(equalTo(\@"foo"), equalTo(\@"bar")))</pre>
* <pre>assertThat(myDictionary, hasEntry(\@"foo", \@"bar"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasEntry instead.
*/
static inline id hasEntry(id keyMatcher, id valueMatcher)
{
return HC_hasEntry(keyMatcher, valueMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,56 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContaining.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContaining ()
@property (nonatomic, strong, readonly) id <HCMatcher> keyMatcher;
@property (nonatomic, strong, readonly) id <HCMatcher> valueMatcher;
@end
@implementation HCIsDictionaryContaining
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher
valueMatcher:(id <HCMatcher>)valueMatcher
{
self = [super init];
if (self)
{
_keyMatcher = keyMatcher;
_valueMatcher = valueMatcher;
}
return self;
}
- (BOOL)matches:(id)dict
{
if ([dict isKindOfClass:[NSDictionary class]])
for (id oneKey in dict)
if ([self.keyMatcher matches:oneKey] && [self.valueMatcher matches:dict[oneKey]])
return YES;
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[[description appendText:@"a dictionary containing { "]
appendDescriptionOf:self.keyMatcher]
appendText:@" = "]
appendDescriptionOf:self.valueMatcher]
appendText:@"; }"];
}
@end
id HC_hasEntry(id keyMatcher, id valueMatcher)
{
HCRequireNonNilObject(keyMatcher);
HCRequireNonNilObject(valueMatcher);
return [[HCIsDictionaryContaining alloc] initWithKeyMatcher:HCWrapInMatcher(keyMatcher)
valueMatcher:HCWrapInMatcher(valueMatcher)];
}

View File

@@ -0,0 +1,68 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if dictionary contains entries that satisfy the list of keys and value
* matchers.
*/
@interface HCIsDictionaryContainingEntries : HCDiagnosingMatcher
- (instancetype)initWithKeys:(NSArray *)keys
valueMatchers:(NSArray<id <HCMatcher>> *)valueMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasEntriesIn(NSDictionary *valueMatchersForKeys);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* entries satisfying a dictionary of keys and their value matchers.
* @param valueMatchersForKeys A dictionary of keys (not matchers) and their value matchers. Any
* value argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to
* check for equality.
* @discussion
* <b>Examples</b><br />
* <pre>assertThat(personDict, hasEntriesIn(\@{\@"firstName": equalTo(\@"Jon"), \@"lastName": equalTo(\@"Reid")}))</pre>
* <pre>assertThat(personDict, hasEntriesIn(\@{\@"firstName": \@"Jon", \@"lastName": \@"Reid"}))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasEntryIn instead.
*/
static inline id hasEntriesIn(NSDictionary *valueMatchersForKeys)
{
return HC_hasEntriesIn(valueMatchersForKeys);
}
#endif
FOUNDATION_EXPORT id HC_hasEntries(id keysAndValueMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* entries satisfying a list of alternating keys and their value matchers.
* @param keysAndValueMatchers... A key (not a matcher) to look up, followed by a value matcher or
* an expected value for <em>equalTo</em> matching, in a comma-separated list ending
* with <code>nil</code>
* @discussion Note that the keys must be actual keys, not matchers. Any value argument that is not
* a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(personDict, hasEntries(\@"firstName", equalTo(\@"Jon"), \@"lastName", equalTo(\@"Reid"), nil))</pre>
* <pre>assertThat(personDict, hasEntries(\@"firstName", \@"Jon", \@"lastName", \@"Reid", nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasEntry instead.
*/
#define hasEntries(keysAndValueMatchers...) HC_hasEntries(keysAndValueMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,132 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContainingEntries.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContainingEntries ()
@property (nonatomic, copy, readonly) NSArray *keys;
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *valueMatchers;
@end
@implementation HCIsDictionaryContainingEntries
- (instancetype)initWithKeys:(NSArray *)keys
valueMatchers:(NSArray<id <HCMatcher>> *)valueMatchers
{
self = [super init];
if (self)
{
_keys = [keys copy];
_valueMatchers = [valueMatchers copy];
}
return self;
}
- (BOOL)matches:(id)dict describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![dict isKindOfClass:[NSDictionary class]])
{
[[mismatchDescription appendText:@"was non-dictionary "] appendDescriptionOf:dict];
return NO;
}
NSUInteger count = self.keys.count;
for (NSUInteger index = 0; index < count; ++index)
{
id key = self.keys[index];
if (dict[key] == nil)
{
[[[[mismatchDescription appendText:@"no "]
appendDescriptionOf:key]
appendText:@" key in "]
appendDescriptionOf:dict];
return NO;
}
id valueMatcher = self.valueMatchers[index];
id actualValue = dict[key];
if (![valueMatcher matches:actualValue])
{
[[[[mismatchDescription appendText:@"value for "]
appendDescriptionOf:key]
appendText:@" was "]
appendDescriptionOf:actualValue];
return NO;
}
}
return YES;
}
- (void)describeKeyValueAtIndex:(NSUInteger)index to:(id <HCDescription>)description
{
[[[[description appendDescriptionOf:self.keys[index]]
appendText:@" = "]
appendDescriptionOf:self.valueMatchers[index]]
appendText:@"; "];
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendText:@"a dictionary containing { "];
NSUInteger count = [self.keys count];
NSUInteger index = 0;
for (; index < count - 1; ++index)
[self describeKeyValueAtIndex:index to:description];
[self describeKeyValueAtIndex:index to:description];
[description appendText:@"}"];
}
@end
static void requirePairedObject(id obj)
{
if (obj == nil)
{
@throw [NSException exceptionWithName:@"NilObject"
reason:@"HC_hasEntries keys and value matchers must be paired"
userInfo:nil];
}
}
id HC_hasEntriesIn(NSDictionary *valueMatchersForKeys)
{
NSArray *keys = valueMatchersForKeys.allKeys;
NSMutableArray<id <HCMatcher>> *valueMatchers = [[NSMutableArray alloc] init];
for (id key in keys)
[valueMatchers addObject:HCWrapInMatcher(valueMatchersForKeys[key])];
return [[HCIsDictionaryContainingEntries alloc] initWithKeys:keys
valueMatchers:valueMatchers];
}
id HC_hasEntries(id keysAndValueMatchers, ...)
{
va_list args;
va_start(args, keysAndValueMatchers);
id key = keysAndValueMatchers;
id valueMatcher = va_arg(args, id);
requirePairedObject(valueMatcher);
NSMutableArray *keys = [NSMutableArray arrayWithObject:key];
NSMutableArray<id <HCMatcher>> *valueMatchers = [NSMutableArray arrayWithObject:HCWrapInMatcher(valueMatcher)];
key = va_arg(args, id);
while (key != nil)
{
[keys addObject:key];
valueMatcher = va_arg(args, id);
requirePairedObject(valueMatcher);
[valueMatchers addObject:HCWrapInMatcher(valueMatcher)];
key = va_arg(args, id);
}
return [[HCIsDictionaryContainingEntries alloc] initWithKeys:keys
valueMatchers:valueMatchers];
}

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any entry in a dictionary has a key satisfying the nested matcher.
*/
@interface HCIsDictionaryContainingKey : HCBaseMatcher
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasKey(id keyMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* at least key that satisfies the specified matcher.
* @param keyMatcher The matcher to satisfy for the key, or an expected value for <em>equalTo</em> matching.
* @discussion Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em>
* matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(myDictionary, hasEntry(equalTo(\@"foo")))</pre>
* <pre>assertThat(myDictionary, hasEntry(\@"foo"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasKey instead.
*/
static inline id hasKey(id keyMatcher)
{
return HC_hasKey(keyMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContainingKey.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContainingKey ()
@property (nonatomic, strong, readonly) id <HCMatcher> keyMatcher;
@end
@implementation HCIsDictionaryContainingKey
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher
{
self = [super init];
if (self)
_keyMatcher = keyMatcher;
return self;
}
- (BOOL)matches:(id)dict
{
if ([dict isKindOfClass:[NSDictionary class]])
for (id oneKey in dict)
if ([self.keyMatcher matches:oneKey])
return YES;
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a dictionary containing key "]
appendDescriptionOf:self.keyMatcher];
}
@end
id HC_hasKey(id keyMatcher)
{
HCRequireNonNilObject(keyMatcher);
return [[HCIsDictionaryContainingKey alloc] initWithKeyMatcher:HCWrapInMatcher(keyMatcher)];
}

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any entry in a dictionary has a value satisfying the nested matcher.
*/
@interface HCIsDictionaryContainingValue : HCBaseMatcher
- (instancetype)initWithValueMatcher:(id <HCMatcher>)valueMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasValue(id valueMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* at least value that satisfies the specified matcher.
* @param valueMatcher The matcher to satisfy for the value, or an expected value for <em>equalTo</em> matching.
* @discussion This matcher works on any collection that has an <code>-allValues</code> method.
*
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(myDictionary, hasValue(equalTo(\@"bar")))</pre>
* <pre>assertThat(myDictionary, hasValue(\@"bar"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasValue instead.
*/
static inline id hasValue(id valueMatcher)
{
return HC_hasValue(valueMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContainingValue.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContainingValue ()
@property (nonatomic, strong, readonly) id <HCMatcher> valueMatcher;
@end
@implementation HCIsDictionaryContainingValue
- (instancetype)initWithValueMatcher:(id <HCMatcher>)valueMatcher
{
self = [super init];
if (self)
_valueMatcher = valueMatcher;
return self;
}
- (BOOL)matches:(id)dict
{
if ([dict respondsToSelector:@selector(allValues)])
for (id oneValue in [dict allValues])
if ([self.valueMatcher matches:oneValue])
return YES;
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a dictionary containing value "]
appendDescriptionOf:self.valueMatcher];
}
@end
id HC_hasValue(id valueMatcher)
{
HCRequireNonNilObject(valueMatcher);
return [[HCIsDictionaryContainingValue alloc] initWithValueMatcher:HCWrapInMatcher(valueMatcher)];
}

View File

@@ -0,0 +1,39 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCHasCount.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches empty collections.
*/
@interface HCIsEmptyCollection : HCHasCount
- (instancetype)init;
@end
FOUNDATION_EXPORT id HC_isEmpty(void);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches any examined object whose <code>-count</code> method
* returns zero.
*
* <b>Example</b><br />
* <pre>assertThat(\@[], isEmpty())</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_isEmpty instead.
*/
static inline id isEmpty(void)
{
return HC_isEmpty();
}
#endif
NS_ASSUME_NONNULL_END

Some files were not shown because too many files have changed in this diff Show More