├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md └── TicTacToe ├── TicTacToe.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── TicTacToe ├── AppDelegate.h ├── AppDelegate.m ├── Classes │ ├── EndGameViewController.h │ ├── EndGameViewController.m │ ├── GameViewController.h │ ├── GameViewController.m │ ├── infrastructure │ │ ├── CHPresenter.h │ │ ├── CHPresenter.m │ │ ├── CHViewController.h │ │ └── CHViewController.m │ ├── model │ │ ├── ComputerPlayer.h │ │ ├── ComputerPlayer.m │ │ ├── GameStates.h │ │ ├── TicTacToeBoard.h │ │ └── TicTacToeBoard.m │ ├── presenters │ │ ├── EndGamePresenter.h │ │ ├── EndGamePresenter.m │ │ ├── GamePresenter.h │ │ ├── GamePresenter.m │ │ ├── HomePresenter.h │ │ └── HomePresenter.m │ ├── viewcontrollers │ │ ├── HomeViewController.h │ │ └── HomeViewController.m │ └── views │ │ ├── EndGameView.h │ │ ├── EndGameView.m │ │ ├── GameView.h │ │ ├── GameView.m │ │ ├── HomeView.h │ │ ├── HomeView.m │ │ ├── TicTacToeButton.h │ │ └── TicTacToeButton.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist └── main.m ├── TicTacToeKIFTests ├── Info.plist ├── TicTacToeTests.h └── TicTacToeTests.m ├── TicTacToeTests ├── Info.plist ├── infrastructure │ ├── CHPresenterTest.m │ └── CHViewControllerTest.m ├── model │ ├── ComputerPlayerTest.m │ └── TicTacToeBoardTest.m ├── presenters │ ├── EndGamePresenterTest.m │ ├── GamePresenterTest.m │ └── HomePresenterTest.m ├── viewcontrollers │ ├── EndGameViewControllerTest.m │ ├── GameViewControllerTest.m │ └── HomeViewControllerTest.m └── views │ └── GameViewTest.m └── includes ├── OCMock ├── NSNotificationCenter+OCMAdditions.h ├── OCMArg.h ├── OCMConstraint.h ├── OCMLocation.h ├── OCMMacroState.h ├── OCMRecorder.h ├── OCMStubRecorder.h ├── OCMock.h └── OCMockObject.h └── libOCMock.a /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "KIF"] 2 | path = KIF 3 | url = git://github.com/catehstn/KIF.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 catehstn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ios-unit-testing 2 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4CCCD8AD1A8CEC7A00AB451F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8AC1A8CEC7A00AB451F /* main.m */; }; 11 | 4CCCD8B01A8CEC7A00AB451F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8AF1A8CEC7A00AB451F /* AppDelegate.m */; }; 12 | 4CCCD8B81A8CEC7A00AB451F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4CCCD8B71A8CEC7A00AB451F /* Images.xcassets */; }; 13 | 4CCCD8D71A8CEE1200AB451F /* CHPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8D41A8CEE1200AB451F /* CHPresenter.m */; }; 14 | 4CCCD8D81A8CEE1200AB451F /* CHViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8D61A8CEE1200AB451F /* CHViewController.m */; }; 15 | 4CCCD8DD1A8CF5E100AB451F /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8DC1A8CF5E100AB451F /* HomeViewController.m */; }; 16 | 4CCCD8E11A8CF69600AB451F /* HomePresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8E01A8CF69600AB451F /* HomePresenter.m */; }; 17 | 4CCCD8E71A8CFF0400AB451F /* TicTacToeBoard.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8E61A8CFF0400AB451F /* TicTacToeBoard.m */; }; 18 | 4CCCD8EB1A8D099B00AB451F /* ComputerPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8EA1A8D099B00AB451F /* ComputerPlayer.m */; }; 19 | 4CCCD8EF1A93B7E900AB451F /* TicTacToeBoardTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8EE1A93B7E900AB451F /* TicTacToeBoardTest.m */; }; 20 | 4CCCD8F21A94C88A00AB451F /* ComputerPlayerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8F11A94C88A00AB451F /* ComputerPlayerTest.m */; }; 21 | 4CCCD8FA1A94CDAC00AB451F /* HomeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8F81A94CDAC00AB451F /* HomeView.m */; }; 22 | 4CCCD8FD1A94D56F00AB451F /* GameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8FC1A94D56F00AB451F /* GameView.m */; }; 23 | 4CCCD9001A94D90C00AB451F /* GamePresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD8FF1A94D90C00AB451F /* GamePresenter.m */; }; 24 | 4CCCD9031A94D92F00AB451F /* GameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9021A94D92F00AB451F /* GameViewController.m */; }; 25 | 4CCCD9061A94DD5C00AB451F /* TicTacToeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9051A94DD5C00AB451F /* TicTacToeButton.m */; }; 26 | 4CCCD9091A962CC500AB451F /* EndGamePresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9081A962CC500AB451F /* EndGamePresenter.m */; }; 27 | 4CCCD90C1A962CDB00AB451F /* EndGameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD90B1A962CDB00AB451F /* EndGameViewController.m */; }; 28 | 4CCCD9191A976F6400AB451F /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CCCD90E1A976F6400AB451F /* libOCMock.a */; }; 29 | 4CCCD91A1A976F9900AB451F /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CCCD90E1A976F6400AB451F /* libOCMock.a */; }; 30 | 4CCCD91D1A97722B00AB451F /* GameViewTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD91C1A97722B00AB451F /* GameViewTest.m */; }; 31 | 4CCCD9221A97777400AB451F /* CHPresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9211A97777400AB451F /* CHPresenterTest.m */; }; 32 | 4CCCD9241A97791800AB451F /* CHViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9231A97791800AB451F /* CHViewControllerTest.m */; }; 33 | 4CCCD9261A9779CC00AB451F /* HomePresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9251A9779CC00AB451F /* HomePresenterTest.m */; }; 34 | 4CCCD9281A978A6500AB451F /* GamePresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9271A978A6500AB451F /* GamePresenterTest.m */; }; 35 | 4CCCD92A1A97930B00AB451F /* EndGamePresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9291A97930B00AB451F /* EndGamePresenterTest.m */; }; 36 | 4CCCD92C1A9795F000AB451F /* HomeViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD92B1A9795F000AB451F /* HomeViewControllerTest.m */; }; 37 | 4CCCD92E1A97A76F00AB451F /* GameViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD92D1A97A76F00AB451F /* GameViewControllerTest.m */; }; 38 | 4CCCD9301A97A8B900AB451F /* EndGameViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD92F1A97A8B900AB451F /* EndGameViewControllerTest.m */; }; 39 | 4CCCD9331A9B10AE00AB451F /* EndGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCD9321A9B10AE00AB451F /* EndGameView.m */; }; 40 | 4CE037C11AA77AA10046956E /* TicTacToeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE037C01AA77AA10046956E /* TicTacToeTests.m */; }; 41 | 4CE037CF1AA77B830046956E /* libKIF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE037CA1AA77B0D0046956E /* libKIF.a */; }; 42 | 4CE037D11AA77B8A0046956E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE037D01AA77B8A0046956E /* CoreGraphics.framework */; }; 43 | /* End PBXBuildFile section */ 44 | 45 | /* Begin PBXContainerItemProxy section */ 46 | 4CCCD8C11A8CEC7A00AB451F /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = 4CCCD89F1A8CEC7A00AB451F /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = 4CCCD8A61A8CEC7A00AB451F; 51 | remoteInfo = TicTacToe; 52 | }; 53 | 4CE037BA1AA77A650046956E /* PBXContainerItemProxy */ = { 54 | isa = PBXContainerItemProxy; 55 | containerPortal = 4CCCD89F1A8CEC7A00AB451F /* Project object */; 56 | proxyType = 1; 57 | remoteGlobalIDString = 4CCCD8A61A8CEC7A00AB451F; 58 | remoteInfo = TicTacToe; 59 | }; 60 | 4CE037C91AA77B0D0046956E /* PBXContainerItemProxy */ = { 61 | isa = PBXContainerItemProxy; 62 | containerPortal = 4CE037C21AA77B0D0046956E /* KIF.xcodeproj */; 63 | proxyType = 2; 64 | remoteGlobalIDString = EABD46AA1857A0C700A5F081; 65 | remoteInfo = KIF; 66 | }; 67 | 4CE037CB1AA77B0D0046956E /* PBXContainerItemProxy */ = { 68 | isa = PBXContainerItemProxy; 69 | containerPortal = 4CE037C21AA77B0D0046956E /* KIF.xcodeproj */; 70 | proxyType = 2; 71 | remoteGlobalIDString = EB60ECC1177F8C83005A041A; 72 | remoteInfo = "Test Host"; 73 | }; 74 | 4CE037CD1AA77B0D0046956E /* PBXContainerItemProxy */ = { 75 | isa = PBXContainerItemProxy; 76 | containerPortal = 4CE037C21AA77B0D0046956E /* KIF.xcodeproj */; 77 | proxyType = 2; 78 | remoteGlobalIDString = EABD46CD1857A0F300A5F081; 79 | remoteInfo = "KIF Tests"; 80 | }; 81 | /* End PBXContainerItemProxy section */ 82 | 83 | /* Begin PBXFileReference section */ 84 | 4CCCD8A71A8CEC7A00AB451F /* TicTacToe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TicTacToe.app; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | 4CCCD8AB1A8CEC7A00AB451F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86 | 4CCCD8AC1A8CEC7A00AB451F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 87 | 4CCCD8AE1A8CEC7A00AB451F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 88 | 4CCCD8AF1A8CEC7A00AB451F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 89 | 4CCCD8B71A8CEC7A00AB451F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 90 | 4CCCD8C01A8CEC7A00AB451F /* TicTacToeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TicTacToeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 91 | 4CCCD8C51A8CEC7A00AB451F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 92 | 4CCCD8D31A8CEE1200AB451F /* CHPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHPresenter.h; sourceTree = ""; }; 93 | 4CCCD8D41A8CEE1200AB451F /* CHPresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CHPresenter.m; sourceTree = ""; }; 94 | 4CCCD8D51A8CEE1200AB451F /* CHViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHViewController.h; sourceTree = ""; }; 95 | 4CCCD8D61A8CEE1200AB451F /* CHViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CHViewController.m; sourceTree = ""; }; 96 | 4CCCD8DB1A8CF5E100AB451F /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HomeViewController.h; path = viewcontrollers/HomeViewController.h; sourceTree = ""; }; 97 | 4CCCD8DC1A8CF5E100AB451F /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HomeViewController.m; path = viewcontrollers/HomeViewController.m; sourceTree = ""; }; 98 | 4CCCD8DF1A8CF69600AB451F /* HomePresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HomePresenter.h; path = presenters/HomePresenter.h; sourceTree = ""; }; 99 | 4CCCD8E01A8CF69600AB451F /* HomePresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HomePresenter.m; path = presenters/HomePresenter.m; sourceTree = ""; }; 100 | 4CCCD8E51A8CFF0400AB451F /* TicTacToeBoard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TicTacToeBoard.h; path = model/TicTacToeBoard.h; sourceTree = ""; }; 101 | 4CCCD8E61A8CFF0400AB451F /* TicTacToeBoard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TicTacToeBoard.m; path = model/TicTacToeBoard.m; sourceTree = ""; }; 102 | 4CCCD8E91A8D099B00AB451F /* ComputerPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ComputerPlayer.h; path = model/ComputerPlayer.h; sourceTree = ""; }; 103 | 4CCCD8EA1A8D099B00AB451F /* ComputerPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ComputerPlayer.m; path = model/ComputerPlayer.m; sourceTree = ""; }; 104 | 4CCCD8EE1A93B7E900AB451F /* TicTacToeBoardTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TicTacToeBoardTest.m; path = model/TicTacToeBoardTest.m; sourceTree = ""; }; 105 | 4CCCD8F11A94C88A00AB451F /* ComputerPlayerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ComputerPlayerTest.m; path = model/ComputerPlayerTest.m; sourceTree = ""; }; 106 | 4CCCD8F81A94CDAC00AB451F /* HomeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HomeView.m; path = views/HomeView.m; sourceTree = ""; }; 107 | 4CCCD8F91A94CDAC00AB451F /* HomeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HomeView.h; path = views/HomeView.h; sourceTree = ""; }; 108 | 4CCCD8FB1A94D56F00AB451F /* GameView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GameView.h; path = views/GameView.h; sourceTree = ""; }; 109 | 4CCCD8FC1A94D56F00AB451F /* GameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GameView.m; path = views/GameView.m; sourceTree = ""; }; 110 | 4CCCD8FE1A94D90C00AB451F /* GamePresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GamePresenter.h; path = presenters/GamePresenter.h; sourceTree = ""; }; 111 | 4CCCD8FF1A94D90C00AB451F /* GamePresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GamePresenter.m; path = presenters/GamePresenter.m; sourceTree = ""; }; 112 | 4CCCD9011A94D92F00AB451F /* GameViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameViewController.h; sourceTree = ""; }; 113 | 4CCCD9021A94D92F00AB451F /* GameViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GameViewController.m; sourceTree = ""; }; 114 | 4CCCD9041A94DD5C00AB451F /* TicTacToeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TicTacToeButton.h; path = views/TicTacToeButton.h; sourceTree = ""; }; 115 | 4CCCD9051A94DD5C00AB451F /* TicTacToeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TicTacToeButton.m; path = views/TicTacToeButton.m; sourceTree = ""; }; 116 | 4CCCD9071A962CC500AB451F /* EndGamePresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EndGamePresenter.h; path = presenters/EndGamePresenter.h; sourceTree = ""; }; 117 | 4CCCD9081A962CC500AB451F /* EndGamePresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EndGamePresenter.m; path = presenters/EndGamePresenter.m; sourceTree = ""; }; 118 | 4CCCD90A1A962CDB00AB451F /* EndGameViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EndGameViewController.h; sourceTree = ""; }; 119 | 4CCCD90B1A962CDB00AB451F /* EndGameViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EndGameViewController.m; sourceTree = ""; }; 120 | 4CCCD90E1A976F6400AB451F /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOCMock.a; sourceTree = ""; }; 121 | 4CCCD9101A976F6400AB451F /* NSNotificationCenter+OCMAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OCMAdditions.h"; sourceTree = ""; }; 122 | 4CCCD9111A976F6400AB451F /* OCMArg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMArg.h; sourceTree = ""; }; 123 | 4CCCD9121A976F6400AB451F /* OCMConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMConstraint.h; sourceTree = ""; }; 124 | 4CCCD9131A976F6400AB451F /* OCMLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMLocation.h; sourceTree = ""; }; 125 | 4CCCD9141A976F6400AB451F /* OCMMacroState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMMacroState.h; sourceTree = ""; }; 126 | 4CCCD9151A976F6400AB451F /* OCMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMock.h; sourceTree = ""; }; 127 | 4CCCD9161A976F6400AB451F /* OCMockObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMockObject.h; sourceTree = ""; }; 128 | 4CCCD9171A976F6400AB451F /* OCMRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMRecorder.h; sourceTree = ""; }; 129 | 4CCCD9181A976F6400AB451F /* OCMStubRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMStubRecorder.h; sourceTree = ""; }; 130 | 4CCCD91C1A97722B00AB451F /* GameViewTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GameViewTest.m; path = views/GameViewTest.m; sourceTree = ""; }; 131 | 4CCCD9211A97777400AB451F /* CHPresenterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CHPresenterTest.m; path = infrastructure/CHPresenterTest.m; sourceTree = ""; }; 132 | 4CCCD9231A97791800AB451F /* CHViewControllerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CHViewControllerTest.m; path = infrastructure/CHViewControllerTest.m; sourceTree = ""; }; 133 | 4CCCD9251A9779CC00AB451F /* HomePresenterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HomePresenterTest.m; path = presenters/HomePresenterTest.m; sourceTree = ""; }; 134 | 4CCCD9271A978A6500AB451F /* GamePresenterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GamePresenterTest.m; path = presenters/GamePresenterTest.m; sourceTree = ""; }; 135 | 4CCCD9291A97930B00AB451F /* EndGamePresenterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EndGamePresenterTest.m; path = presenters/EndGamePresenterTest.m; sourceTree = ""; }; 136 | 4CCCD92B1A9795F000AB451F /* HomeViewControllerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HomeViewControllerTest.m; path = viewcontrollers/HomeViewControllerTest.m; sourceTree = ""; }; 137 | 4CCCD92D1A97A76F00AB451F /* GameViewControllerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GameViewControllerTest.m; path = viewcontrollers/GameViewControllerTest.m; sourceTree = ""; }; 138 | 4CCCD92F1A97A8B900AB451F /* EndGameViewControllerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EndGameViewControllerTest.m; path = viewcontrollers/EndGameViewControllerTest.m; sourceTree = ""; }; 139 | 4CCCD9311A9B10AE00AB451F /* EndGameView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EndGameView.h; path = views/EndGameView.h; sourceTree = ""; }; 140 | 4CCCD9321A9B10AE00AB451F /* EndGameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EndGameView.m; path = views/EndGameView.m; sourceTree = ""; }; 141 | 4CCCD9341A9C7A1C00AB451F /* GameStates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GameStates.h; path = model/GameStates.h; sourceTree = ""; }; 142 | 4CE037B41AA77A650046956E /* TicTacToeKIFTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TicTacToeKIFTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 143 | 4CE037B71AA77A650046956E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 144 | 4CE037BF1AA77AA10046956E /* TicTacToeTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TicTacToeTests.h; sourceTree = ""; }; 145 | 4CE037C01AA77AA10046956E /* TicTacToeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TicTacToeTests.m; sourceTree = ""; }; 146 | 4CE037C21AA77B0D0046956E /* KIF.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KIF.xcodeproj; path = ../../KIF/KIF.xcodeproj; sourceTree = ""; }; 147 | 4CE037D01AA77B8A0046956E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 148 | /* End PBXFileReference section */ 149 | 150 | /* Begin PBXFrameworksBuildPhase section */ 151 | 4CCCD8A41A8CEC7A00AB451F /* Frameworks */ = { 152 | isa = PBXFrameworksBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | 4CCCD9191A976F6400AB451F /* libOCMock.a in Frameworks */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | 4CCCD8BD1A8CEC7A00AB451F /* Frameworks */ = { 160 | isa = PBXFrameworksBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | 4CCCD91A1A976F9900AB451F /* libOCMock.a in Frameworks */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | 4CE037B11AA77A650046956E /* Frameworks */ = { 168 | isa = PBXFrameworksBuildPhase; 169 | buildActionMask = 2147483647; 170 | files = ( 171 | 4CE037D11AA77B8A0046956E /* CoreGraphics.framework in Frameworks */, 172 | 4CE037CF1AA77B830046956E /* libKIF.a in Frameworks */, 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | }; 176 | /* End PBXFrameworksBuildPhase section */ 177 | 178 | /* Begin PBXGroup section */ 179 | 4CCCD89E1A8CEC7A00AB451F = { 180 | isa = PBXGroup; 181 | children = ( 182 | 4CE037D01AA77B8A0046956E /* CoreGraphics.framework */, 183 | 4CCCD90D1A976F6400AB451F /* includes */, 184 | 4CCCD8A91A8CEC7A00AB451F /* TicTacToe */, 185 | 4CCCD8C31A8CEC7A00AB451F /* TicTacToeTests */, 186 | 4CE037B51AA77A650046956E /* TicTacToeKIFTests */, 187 | 4CCCD8A81A8CEC7A00AB451F /* Products */, 188 | ); 189 | sourceTree = ""; 190 | }; 191 | 4CCCD8A81A8CEC7A00AB451F /* Products */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 4CCCD8A71A8CEC7A00AB451F /* TicTacToe.app */, 195 | 4CCCD8C01A8CEC7A00AB451F /* TicTacToeTests.xctest */, 196 | 4CE037B41AA77A650046956E /* TicTacToeKIFTests.xctest */, 197 | ); 198 | name = Products; 199 | sourceTree = ""; 200 | }; 201 | 4CCCD8A91A8CEC7A00AB451F /* TicTacToe */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 4CCCD8D11A8CEE1200AB451F /* Classes */, 205 | 4CCCD8AE1A8CEC7A00AB451F /* AppDelegate.h */, 206 | 4CCCD8AF1A8CEC7A00AB451F /* AppDelegate.m */, 207 | 4CCCD8B71A8CEC7A00AB451F /* Images.xcassets */, 208 | 4CCCD8AA1A8CEC7A00AB451F /* Supporting Files */, 209 | ); 210 | path = TicTacToe; 211 | sourceTree = ""; 212 | }; 213 | 4CCCD8AA1A8CEC7A00AB451F /* Supporting Files */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 4CCCD8AB1A8CEC7A00AB451F /* Info.plist */, 217 | 4CCCD8AC1A8CEC7A00AB451F /* main.m */, 218 | ); 219 | name = "Supporting Files"; 220 | sourceTree = ""; 221 | }; 222 | 4CCCD8C31A8CEC7A00AB451F /* TicTacToeTests */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | 4CCCD9201A97774800AB451F /* infrastructure */, 226 | 4CCCD8F01A93B7F000AB451F /* model */, 227 | 4CCCD91E1A9776F000AB451F /* presenters */, 228 | 4CCCD91F1A97773B00AB451F /* viewcontrollers */, 229 | 4CCCD91B1A9771C000AB451F /* views */, 230 | 4CCCD8C41A8CEC7A00AB451F /* Supporting Files */, 231 | ); 232 | path = TicTacToeTests; 233 | sourceTree = ""; 234 | }; 235 | 4CCCD8C41A8CEC7A00AB451F /* Supporting Files */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | 4CCCD8C51A8CEC7A00AB451F /* Info.plist */, 239 | ); 240 | name = "Supporting Files"; 241 | sourceTree = ""; 242 | }; 243 | 4CCCD8D11A8CEE1200AB451F /* Classes */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | 4CCCD8D21A8CEE1200AB451F /* infrastructure */, 247 | 4CCCD8E41A8CFED300AB451F /* model */, 248 | 4CCCD8E21A8CF6A100AB451F /* presenters */, 249 | 4CCCD8DE1A8CF5E900AB451F /* viewcontrollers */, 250 | 4CCCD8F41A94CBFE00AB451F /* views */, 251 | ); 252 | path = Classes; 253 | sourceTree = ""; 254 | }; 255 | 4CCCD8D21A8CEE1200AB451F /* infrastructure */ = { 256 | isa = PBXGroup; 257 | children = ( 258 | 4CCCD8D31A8CEE1200AB451F /* CHPresenter.h */, 259 | 4CCCD8D41A8CEE1200AB451F /* CHPresenter.m */, 260 | 4CCCD8D51A8CEE1200AB451F /* CHViewController.h */, 261 | 4CCCD8D61A8CEE1200AB451F /* CHViewController.m */, 262 | ); 263 | path = infrastructure; 264 | sourceTree = ""; 265 | }; 266 | 4CCCD8DE1A8CF5E900AB451F /* viewcontrollers */ = { 267 | isa = PBXGroup; 268 | children = ( 269 | 4CCCD8DB1A8CF5E100AB451F /* HomeViewController.h */, 270 | 4CCCD8DC1A8CF5E100AB451F /* HomeViewController.m */, 271 | 4CCCD9011A94D92F00AB451F /* GameViewController.h */, 272 | 4CCCD9021A94D92F00AB451F /* GameViewController.m */, 273 | 4CCCD90A1A962CDB00AB451F /* EndGameViewController.h */, 274 | 4CCCD90B1A962CDB00AB451F /* EndGameViewController.m */, 275 | ); 276 | name = viewcontrollers; 277 | sourceTree = ""; 278 | }; 279 | 4CCCD8E21A8CF6A100AB451F /* presenters */ = { 280 | isa = PBXGroup; 281 | children = ( 282 | 4CCCD8DF1A8CF69600AB451F /* HomePresenter.h */, 283 | 4CCCD8E01A8CF69600AB451F /* HomePresenter.m */, 284 | 4CCCD8FE1A94D90C00AB451F /* GamePresenter.h */, 285 | 4CCCD8FF1A94D90C00AB451F /* GamePresenter.m */, 286 | 4CCCD9071A962CC500AB451F /* EndGamePresenter.h */, 287 | 4CCCD9081A962CC500AB451F /* EndGamePresenter.m */, 288 | ); 289 | name = presenters; 290 | sourceTree = ""; 291 | }; 292 | 4CCCD8E41A8CFED300AB451F /* model */ = { 293 | isa = PBXGroup; 294 | children = ( 295 | 4CCCD8E51A8CFF0400AB451F /* TicTacToeBoard.h */, 296 | 4CCCD8E61A8CFF0400AB451F /* TicTacToeBoard.m */, 297 | 4CCCD8E91A8D099B00AB451F /* ComputerPlayer.h */, 298 | 4CCCD8EA1A8D099B00AB451F /* ComputerPlayer.m */, 299 | 4CCCD9341A9C7A1C00AB451F /* GameStates.h */, 300 | ); 301 | name = model; 302 | sourceTree = ""; 303 | }; 304 | 4CCCD8F01A93B7F000AB451F /* model */ = { 305 | isa = PBXGroup; 306 | children = ( 307 | 4CCCD8EE1A93B7E900AB451F /* TicTacToeBoardTest.m */, 308 | 4CCCD8F11A94C88A00AB451F /* ComputerPlayerTest.m */, 309 | ); 310 | name = model; 311 | sourceTree = ""; 312 | }; 313 | 4CCCD8F41A94CBFE00AB451F /* views */ = { 314 | isa = PBXGroup; 315 | children = ( 316 | 4CCCD8F91A94CDAC00AB451F /* HomeView.h */, 317 | 4CCCD8F81A94CDAC00AB451F /* HomeView.m */, 318 | 4CCCD8FB1A94D56F00AB451F /* GameView.h */, 319 | 4CCCD8FC1A94D56F00AB451F /* GameView.m */, 320 | 4CCCD9041A94DD5C00AB451F /* TicTacToeButton.h */, 321 | 4CCCD9051A94DD5C00AB451F /* TicTacToeButton.m */, 322 | 4CCCD9311A9B10AE00AB451F /* EndGameView.h */, 323 | 4CCCD9321A9B10AE00AB451F /* EndGameView.m */, 324 | ); 325 | name = views; 326 | sourceTree = ""; 327 | }; 328 | 4CCCD90D1A976F6400AB451F /* includes */ = { 329 | isa = PBXGroup; 330 | children = ( 331 | 4CCCD90E1A976F6400AB451F /* libOCMock.a */, 332 | 4CCCD90F1A976F6400AB451F /* OCMock */, 333 | ); 334 | path = includes; 335 | sourceTree = ""; 336 | }; 337 | 4CCCD90F1A976F6400AB451F /* OCMock */ = { 338 | isa = PBXGroup; 339 | children = ( 340 | 4CCCD9101A976F6400AB451F /* NSNotificationCenter+OCMAdditions.h */, 341 | 4CCCD9111A976F6400AB451F /* OCMArg.h */, 342 | 4CCCD9121A976F6400AB451F /* OCMConstraint.h */, 343 | 4CCCD9131A976F6400AB451F /* OCMLocation.h */, 344 | 4CCCD9141A976F6400AB451F /* OCMMacroState.h */, 345 | 4CCCD9151A976F6400AB451F /* OCMock.h */, 346 | 4CCCD9161A976F6400AB451F /* OCMockObject.h */, 347 | 4CCCD9171A976F6400AB451F /* OCMRecorder.h */, 348 | 4CCCD9181A976F6400AB451F /* OCMStubRecorder.h */, 349 | ); 350 | path = OCMock; 351 | sourceTree = ""; 352 | }; 353 | 4CCCD91B1A9771C000AB451F /* views */ = { 354 | isa = PBXGroup; 355 | children = ( 356 | 4CCCD91C1A97722B00AB451F /* GameViewTest.m */, 357 | ); 358 | name = views; 359 | sourceTree = ""; 360 | }; 361 | 4CCCD91E1A9776F000AB451F /* presenters */ = { 362 | isa = PBXGroup; 363 | children = ( 364 | 4CCCD9251A9779CC00AB451F /* HomePresenterTest.m */, 365 | 4CCCD9271A978A6500AB451F /* GamePresenterTest.m */, 366 | 4CCCD9291A97930B00AB451F /* EndGamePresenterTest.m */, 367 | ); 368 | name = presenters; 369 | sourceTree = ""; 370 | }; 371 | 4CCCD91F1A97773B00AB451F /* viewcontrollers */ = { 372 | isa = PBXGroup; 373 | children = ( 374 | 4CCCD92B1A9795F000AB451F /* HomeViewControllerTest.m */, 375 | 4CCCD92D1A97A76F00AB451F /* GameViewControllerTest.m */, 376 | 4CCCD92F1A97A8B900AB451F /* EndGameViewControllerTest.m */, 377 | ); 378 | name = viewcontrollers; 379 | sourceTree = ""; 380 | }; 381 | 4CCCD9201A97774800AB451F /* infrastructure */ = { 382 | isa = PBXGroup; 383 | children = ( 384 | 4CCCD9211A97777400AB451F /* CHPresenterTest.m */, 385 | 4CCCD9231A97791800AB451F /* CHViewControllerTest.m */, 386 | ); 387 | name = infrastructure; 388 | sourceTree = ""; 389 | }; 390 | 4CE037B51AA77A650046956E /* TicTacToeKIFTests */ = { 391 | isa = PBXGroup; 392 | children = ( 393 | 4CE037C21AA77B0D0046956E /* KIF.xcodeproj */, 394 | 4CE037B61AA77A650046956E /* Supporting Files */, 395 | 4CE037BF1AA77AA10046956E /* TicTacToeTests.h */, 396 | 4CE037C01AA77AA10046956E /* TicTacToeTests.m */, 397 | ); 398 | path = TicTacToeKIFTests; 399 | sourceTree = ""; 400 | }; 401 | 4CE037B61AA77A650046956E /* Supporting Files */ = { 402 | isa = PBXGroup; 403 | children = ( 404 | 4CE037B71AA77A650046956E /* Info.plist */, 405 | ); 406 | name = "Supporting Files"; 407 | sourceTree = ""; 408 | }; 409 | 4CE037C31AA77B0D0046956E /* Products */ = { 410 | isa = PBXGroup; 411 | children = ( 412 | 4CE037CA1AA77B0D0046956E /* libKIF.a */, 413 | 4CE037CC1AA77B0D0046956E /* Test Host.app */, 414 | 4CE037CE1AA77B0D0046956E /* KIF Tests - XCTest.xctest */, 415 | ); 416 | name = Products; 417 | sourceTree = ""; 418 | }; 419 | /* End PBXGroup section */ 420 | 421 | /* Begin PBXNativeTarget section */ 422 | 4CCCD8A61A8CEC7A00AB451F /* TicTacToe */ = { 423 | isa = PBXNativeTarget; 424 | buildConfigurationList = 4CCCD8CA1A8CEC7A00AB451F /* Build configuration list for PBXNativeTarget "TicTacToe" */; 425 | buildPhases = ( 426 | 4CCCD8A31A8CEC7A00AB451F /* Sources */, 427 | 4CCCD8A41A8CEC7A00AB451F /* Frameworks */, 428 | 4CCCD8A51A8CEC7A00AB451F /* Resources */, 429 | ); 430 | buildRules = ( 431 | ); 432 | dependencies = ( 433 | ); 434 | name = TicTacToe; 435 | productName = TicTacToe; 436 | productReference = 4CCCD8A71A8CEC7A00AB451F /* TicTacToe.app */; 437 | productType = "com.apple.product-type.application"; 438 | }; 439 | 4CCCD8BF1A8CEC7A00AB451F /* TicTacToeTests */ = { 440 | isa = PBXNativeTarget; 441 | buildConfigurationList = 4CCCD8CD1A8CEC7A00AB451F /* Build configuration list for PBXNativeTarget "TicTacToeTests" */; 442 | buildPhases = ( 443 | 4CCCD8BC1A8CEC7A00AB451F /* Sources */, 444 | 4CCCD8BD1A8CEC7A00AB451F /* Frameworks */, 445 | 4CCCD8BE1A8CEC7A00AB451F /* Resources */, 446 | ); 447 | buildRules = ( 448 | ); 449 | dependencies = ( 450 | 4CCCD8C21A8CEC7A00AB451F /* PBXTargetDependency */, 451 | ); 452 | name = TicTacToeTests; 453 | productName = TicTacToeTests; 454 | productReference = 4CCCD8C01A8CEC7A00AB451F /* TicTacToeTests.xctest */; 455 | productType = "com.apple.product-type.bundle.unit-test"; 456 | }; 457 | 4CE037B31AA77A650046956E /* TicTacToeKIFTests */ = { 458 | isa = PBXNativeTarget; 459 | buildConfigurationList = 4CE037BC1AA77A650046956E /* Build configuration list for PBXNativeTarget "TicTacToeKIFTests" */; 460 | buildPhases = ( 461 | 4CE037B01AA77A650046956E /* Sources */, 462 | 4CE037B11AA77A650046956E /* Frameworks */, 463 | 4CE037B21AA77A650046956E /* Resources */, 464 | ); 465 | buildRules = ( 466 | ); 467 | dependencies = ( 468 | 4CE037BB1AA77A650046956E /* PBXTargetDependency */, 469 | ); 470 | name = TicTacToeKIFTests; 471 | productName = TicTacToeKIFTests; 472 | productReference = 4CE037B41AA77A650046956E /* TicTacToeKIFTests.xctest */; 473 | productType = "com.apple.product-type.bundle.unit-test"; 474 | }; 475 | /* End PBXNativeTarget section */ 476 | 477 | /* Begin PBXProject section */ 478 | 4CCCD89F1A8CEC7A00AB451F /* Project object */ = { 479 | isa = PBXProject; 480 | attributes = { 481 | LastUpgradeCheck = 0610; 482 | ORGANIZATIONNAME = catehuston.com; 483 | TargetAttributes = { 484 | 4CCCD8A61A8CEC7A00AB451F = { 485 | CreatedOnToolsVersion = 6.1.1; 486 | }; 487 | 4CCCD8BF1A8CEC7A00AB451F = { 488 | CreatedOnToolsVersion = 6.1.1; 489 | TestTargetID = 4CCCD8A61A8CEC7A00AB451F; 490 | }; 491 | 4CE037B31AA77A650046956E = { 492 | CreatedOnToolsVersion = 6.1.1; 493 | TestTargetID = 4CCCD8A61A8CEC7A00AB451F; 494 | }; 495 | }; 496 | }; 497 | buildConfigurationList = 4CCCD8A21A8CEC7A00AB451F /* Build configuration list for PBXProject "TicTacToe" */; 498 | compatibilityVersion = "Xcode 3.2"; 499 | developmentRegion = English; 500 | hasScannedForEncodings = 0; 501 | knownRegions = ( 502 | en, 503 | Base, 504 | ); 505 | mainGroup = 4CCCD89E1A8CEC7A00AB451F; 506 | productRefGroup = 4CCCD8A81A8CEC7A00AB451F /* Products */; 507 | projectDirPath = ""; 508 | projectReferences = ( 509 | { 510 | ProductGroup = 4CE037C31AA77B0D0046956E /* Products */; 511 | ProjectRef = 4CE037C21AA77B0D0046956E /* KIF.xcodeproj */; 512 | }, 513 | ); 514 | projectRoot = ""; 515 | targets = ( 516 | 4CCCD8A61A8CEC7A00AB451F /* TicTacToe */, 517 | 4CCCD8BF1A8CEC7A00AB451F /* TicTacToeTests */, 518 | 4CE037B31AA77A650046956E /* TicTacToeKIFTests */, 519 | ); 520 | }; 521 | /* End PBXProject section */ 522 | 523 | /* Begin PBXReferenceProxy section */ 524 | 4CE037CA1AA77B0D0046956E /* libKIF.a */ = { 525 | isa = PBXReferenceProxy; 526 | fileType = archive.ar; 527 | path = libKIF.a; 528 | remoteRef = 4CE037C91AA77B0D0046956E /* PBXContainerItemProxy */; 529 | sourceTree = BUILT_PRODUCTS_DIR; 530 | }; 531 | 4CE037CC1AA77B0D0046956E /* Test Host.app */ = { 532 | isa = PBXReferenceProxy; 533 | fileType = wrapper.application; 534 | path = "Test Host.app"; 535 | remoteRef = 4CE037CB1AA77B0D0046956E /* PBXContainerItemProxy */; 536 | sourceTree = BUILT_PRODUCTS_DIR; 537 | }; 538 | 4CE037CE1AA77B0D0046956E /* KIF Tests - XCTest.xctest */ = { 539 | isa = PBXReferenceProxy; 540 | fileType = wrapper.cfbundle; 541 | path = "KIF Tests - XCTest.xctest"; 542 | remoteRef = 4CE037CD1AA77B0D0046956E /* PBXContainerItemProxy */; 543 | sourceTree = BUILT_PRODUCTS_DIR; 544 | }; 545 | /* End PBXReferenceProxy section */ 546 | 547 | /* Begin PBXResourcesBuildPhase section */ 548 | 4CCCD8A51A8CEC7A00AB451F /* Resources */ = { 549 | isa = PBXResourcesBuildPhase; 550 | buildActionMask = 2147483647; 551 | files = ( 552 | 4CCCD8B81A8CEC7A00AB451F /* Images.xcassets in Resources */, 553 | ); 554 | runOnlyForDeploymentPostprocessing = 0; 555 | }; 556 | 4CCCD8BE1A8CEC7A00AB451F /* Resources */ = { 557 | isa = PBXResourcesBuildPhase; 558 | buildActionMask = 2147483647; 559 | files = ( 560 | ); 561 | runOnlyForDeploymentPostprocessing = 0; 562 | }; 563 | 4CE037B21AA77A650046956E /* Resources */ = { 564 | isa = PBXResourcesBuildPhase; 565 | buildActionMask = 2147483647; 566 | files = ( 567 | ); 568 | runOnlyForDeploymentPostprocessing = 0; 569 | }; 570 | /* End PBXResourcesBuildPhase section */ 571 | 572 | /* Begin PBXSourcesBuildPhase section */ 573 | 4CCCD8A31A8CEC7A00AB451F /* Sources */ = { 574 | isa = PBXSourcesBuildPhase; 575 | buildActionMask = 2147483647; 576 | files = ( 577 | 4CCCD8FA1A94CDAC00AB451F /* HomeView.m in Sources */, 578 | 4CCCD9001A94D90C00AB451F /* GamePresenter.m in Sources */, 579 | 4CCCD8D71A8CEE1200AB451F /* CHPresenter.m in Sources */, 580 | 4CCCD8D81A8CEE1200AB451F /* CHViewController.m in Sources */, 581 | 4CCCD9331A9B10AE00AB451F /* EndGameView.m in Sources */, 582 | 4CCCD90C1A962CDB00AB451F /* EndGameViewController.m in Sources */, 583 | 4CCCD9031A94D92F00AB451F /* GameViewController.m in Sources */, 584 | 4CCCD8B01A8CEC7A00AB451F /* AppDelegate.m in Sources */, 585 | 4CCCD8AD1A8CEC7A00AB451F /* main.m in Sources */, 586 | 4CCCD8E11A8CF69600AB451F /* HomePresenter.m in Sources */, 587 | 4CCCD9061A94DD5C00AB451F /* TicTacToeButton.m in Sources */, 588 | 4CCCD8FD1A94D56F00AB451F /* GameView.m in Sources */, 589 | 4CCCD8E71A8CFF0400AB451F /* TicTacToeBoard.m in Sources */, 590 | 4CCCD8DD1A8CF5E100AB451F /* HomeViewController.m in Sources */, 591 | 4CCCD9091A962CC500AB451F /* EndGamePresenter.m in Sources */, 592 | 4CCCD8EB1A8D099B00AB451F /* ComputerPlayer.m in Sources */, 593 | ); 594 | runOnlyForDeploymentPostprocessing = 0; 595 | }; 596 | 4CCCD8BC1A8CEC7A00AB451F /* Sources */ = { 597 | isa = PBXSourcesBuildPhase; 598 | buildActionMask = 2147483647; 599 | files = ( 600 | 4CCCD92E1A97A76F00AB451F /* GameViewControllerTest.m in Sources */, 601 | 4CCCD9301A97A8B900AB451F /* EndGameViewControllerTest.m in Sources */, 602 | 4CCCD8EF1A93B7E900AB451F /* TicTacToeBoardTest.m in Sources */, 603 | 4CCCD91D1A97722B00AB451F /* GameViewTest.m in Sources */, 604 | 4CCCD92A1A97930B00AB451F /* EndGamePresenterTest.m in Sources */, 605 | 4CCCD8F21A94C88A00AB451F /* ComputerPlayerTest.m in Sources */, 606 | 4CCCD9241A97791800AB451F /* CHViewControllerTest.m in Sources */, 607 | 4CCCD9221A97777400AB451F /* CHPresenterTest.m in Sources */, 608 | 4CCCD9281A978A6500AB451F /* GamePresenterTest.m in Sources */, 609 | 4CCCD92C1A9795F000AB451F /* HomeViewControllerTest.m in Sources */, 610 | 4CCCD9261A9779CC00AB451F /* HomePresenterTest.m in Sources */, 611 | ); 612 | runOnlyForDeploymentPostprocessing = 0; 613 | }; 614 | 4CE037B01AA77A650046956E /* Sources */ = { 615 | isa = PBXSourcesBuildPhase; 616 | buildActionMask = 2147483647; 617 | files = ( 618 | 4CE037C11AA77AA10046956E /* TicTacToeTests.m in Sources */, 619 | ); 620 | runOnlyForDeploymentPostprocessing = 0; 621 | }; 622 | /* End PBXSourcesBuildPhase section */ 623 | 624 | /* Begin PBXTargetDependency section */ 625 | 4CCCD8C21A8CEC7A00AB451F /* PBXTargetDependency */ = { 626 | isa = PBXTargetDependency; 627 | target = 4CCCD8A61A8CEC7A00AB451F /* TicTacToe */; 628 | targetProxy = 4CCCD8C11A8CEC7A00AB451F /* PBXContainerItemProxy */; 629 | }; 630 | 4CE037BB1AA77A650046956E /* PBXTargetDependency */ = { 631 | isa = PBXTargetDependency; 632 | target = 4CCCD8A61A8CEC7A00AB451F /* TicTacToe */; 633 | targetProxy = 4CE037BA1AA77A650046956E /* PBXContainerItemProxy */; 634 | }; 635 | /* End PBXTargetDependency section */ 636 | 637 | /* Begin XCBuildConfiguration section */ 638 | 4CCCD8C81A8CEC7A00AB451F /* Debug */ = { 639 | isa = XCBuildConfiguration; 640 | buildSettings = { 641 | ALWAYS_SEARCH_USER_PATHS = NO; 642 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 643 | CLANG_CXX_LIBRARY = "libc++"; 644 | CLANG_ENABLE_MODULES = YES; 645 | CLANG_ENABLE_OBJC_ARC = YES; 646 | CLANG_WARN_BOOL_CONVERSION = YES; 647 | CLANG_WARN_CONSTANT_CONVERSION = YES; 648 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 649 | CLANG_WARN_EMPTY_BODY = YES; 650 | CLANG_WARN_ENUM_CONVERSION = YES; 651 | CLANG_WARN_INT_CONVERSION = YES; 652 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 653 | CLANG_WARN_UNREACHABLE_CODE = YES; 654 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 655 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 656 | COPY_PHASE_STRIP = NO; 657 | ENABLE_STRICT_OBJC_MSGSEND = YES; 658 | GCC_C_LANGUAGE_STANDARD = gnu99; 659 | GCC_DYNAMIC_NO_PIC = NO; 660 | GCC_OPTIMIZATION_LEVEL = 0; 661 | GCC_PREPROCESSOR_DEFINITIONS = ( 662 | "DEBUG=1", 663 | "$(inherited)", 664 | ); 665 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 666 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 667 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 668 | GCC_WARN_UNDECLARED_SELECTOR = YES; 669 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 670 | GCC_WARN_UNUSED_FUNCTION = YES; 671 | GCC_WARN_UNUSED_VARIABLE = YES; 672 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 673 | MTL_ENABLE_DEBUG_INFO = YES; 674 | ONLY_ACTIVE_ARCH = YES; 675 | SDKROOT = iphoneos; 676 | }; 677 | name = Debug; 678 | }; 679 | 4CCCD8C91A8CEC7A00AB451F /* Release */ = { 680 | isa = XCBuildConfiguration; 681 | buildSettings = { 682 | ALWAYS_SEARCH_USER_PATHS = NO; 683 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 684 | CLANG_CXX_LIBRARY = "libc++"; 685 | CLANG_ENABLE_MODULES = YES; 686 | CLANG_ENABLE_OBJC_ARC = YES; 687 | CLANG_WARN_BOOL_CONVERSION = YES; 688 | CLANG_WARN_CONSTANT_CONVERSION = YES; 689 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 690 | CLANG_WARN_EMPTY_BODY = YES; 691 | CLANG_WARN_ENUM_CONVERSION = YES; 692 | CLANG_WARN_INT_CONVERSION = YES; 693 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 694 | CLANG_WARN_UNREACHABLE_CODE = YES; 695 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 696 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 697 | COPY_PHASE_STRIP = YES; 698 | ENABLE_NS_ASSERTIONS = NO; 699 | ENABLE_STRICT_OBJC_MSGSEND = YES; 700 | GCC_C_LANGUAGE_STANDARD = gnu99; 701 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 702 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 703 | GCC_WARN_UNDECLARED_SELECTOR = YES; 704 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 705 | GCC_WARN_UNUSED_FUNCTION = YES; 706 | GCC_WARN_UNUSED_VARIABLE = YES; 707 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 708 | MTL_ENABLE_DEBUG_INFO = NO; 709 | SDKROOT = iphoneos; 710 | VALIDATE_PRODUCT = YES; 711 | }; 712 | name = Release; 713 | }; 714 | 4CCCD8CB1A8CEC7A00AB451F /* Debug */ = { 715 | isa = XCBuildConfiguration; 716 | buildSettings = { 717 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 718 | INFOPLIST_FILE = TicTacToe/Info.plist; 719 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 720 | LIBRARY_SEARCH_PATHS = ( 721 | "$(inherited)", 722 | "$(PROJECT_DIR)/includes", 723 | ); 724 | PRODUCT_NAME = "$(TARGET_NAME)"; 725 | }; 726 | name = Debug; 727 | }; 728 | 4CCCD8CC1A8CEC7A00AB451F /* Release */ = { 729 | isa = XCBuildConfiguration; 730 | buildSettings = { 731 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 732 | INFOPLIST_FILE = TicTacToe/Info.plist; 733 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 734 | LIBRARY_SEARCH_PATHS = ( 735 | "$(inherited)", 736 | "$(PROJECT_DIR)/includes", 737 | ); 738 | PRODUCT_NAME = "$(TARGET_NAME)"; 739 | }; 740 | name = Release; 741 | }; 742 | 4CCCD8CE1A8CEC7A00AB451F /* Debug */ = { 743 | isa = XCBuildConfiguration; 744 | buildSettings = { 745 | BUNDLE_LOADER = "$(TEST_HOST)"; 746 | FRAMEWORK_SEARCH_PATHS = ( 747 | "$(SDKROOT)/Developer/Library/Frameworks", 748 | "$(inherited)", 749 | ); 750 | GCC_PREPROCESSOR_DEFINITIONS = ( 751 | "DEBUG=1", 752 | "$(inherited)", 753 | ); 754 | HEADER_SEARCH_PATHS = ( 755 | "$(inherited)", 756 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 757 | "$(PROJECT_DIR)/includes", 758 | ); 759 | INFOPLIST_FILE = TicTacToeTests/Info.plist; 760 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 761 | LIBRARY_SEARCH_PATHS = ( 762 | "$(inherited)", 763 | "$(PROJECT_DIR)/includes", 764 | ); 765 | OTHER_LDFLAGS = ( 766 | "$(inherited)", 767 | "-framework", 768 | XCTest, 769 | "-ObjC", 770 | ); 771 | PRODUCT_NAME = "$(TARGET_NAME)"; 772 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TicTacToe.app/TicTacToe"; 773 | }; 774 | name = Debug; 775 | }; 776 | 4CCCD8CF1A8CEC7A00AB451F /* Release */ = { 777 | isa = XCBuildConfiguration; 778 | buildSettings = { 779 | BUNDLE_LOADER = "$(TEST_HOST)"; 780 | FRAMEWORK_SEARCH_PATHS = ( 781 | "$(SDKROOT)/Developer/Library/Frameworks", 782 | "$(inherited)", 783 | ); 784 | HEADER_SEARCH_PATHS = ( 785 | "$(inherited)", 786 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 787 | "$(PROJECT_DIR)/includes", 788 | ); 789 | INFOPLIST_FILE = TicTacToeTests/Info.plist; 790 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 791 | LIBRARY_SEARCH_PATHS = ( 792 | "$(inherited)", 793 | "$(PROJECT_DIR)/includes", 794 | ); 795 | OTHER_LDFLAGS = ( 796 | "$(inherited)", 797 | "-framework", 798 | XCTest, 799 | "-ObjC", 800 | ); 801 | PRODUCT_NAME = "$(TARGET_NAME)"; 802 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TicTacToe.app/TicTacToe"; 803 | }; 804 | name = Release; 805 | }; 806 | 4CE037BD1AA77A650046956E /* Debug */ = { 807 | isa = XCBuildConfiguration; 808 | buildSettings = { 809 | BUNDLE_LOADER = "$(TEST_HOST)"; 810 | FRAMEWORK_SEARCH_PATHS = ( 811 | "$(SDKROOT)/Developer/Library/Frameworks", 812 | "$(inherited)", 813 | ); 814 | GCC_PREPROCESSOR_DEFINITIONS = ( 815 | "DEBUG=1", 816 | "$(inherited)", 817 | ); 818 | INFOPLIST_FILE = TicTacToeKIFTests/Info.plist; 819 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 820 | OTHER_LDFLAGS = ( 821 | "$(inherited)", 822 | "-framework", 823 | XCTest, 824 | "-ObjC", 825 | ); 826 | PRODUCT_NAME = "$(TARGET_NAME)"; 827 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TicTacToe.app/TicTacToe"; 828 | }; 829 | name = Debug; 830 | }; 831 | 4CE037BE1AA77A650046956E /* Release */ = { 832 | isa = XCBuildConfiguration; 833 | buildSettings = { 834 | BUNDLE_LOADER = "$(TEST_HOST)"; 835 | FRAMEWORK_SEARCH_PATHS = ( 836 | "$(SDKROOT)/Developer/Library/Frameworks", 837 | "$(inherited)", 838 | ); 839 | INFOPLIST_FILE = TicTacToeKIFTests/Info.plist; 840 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 841 | OTHER_LDFLAGS = ( 842 | "$(inherited)", 843 | "-framework", 844 | XCTest, 845 | "-ObjC", 846 | ); 847 | PRODUCT_NAME = "$(TARGET_NAME)"; 848 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TicTacToe.app/TicTacToe"; 849 | }; 850 | name = Release; 851 | }; 852 | /* End XCBuildConfiguration section */ 853 | 854 | /* Begin XCConfigurationList section */ 855 | 4CCCD8A21A8CEC7A00AB451F /* Build configuration list for PBXProject "TicTacToe" */ = { 856 | isa = XCConfigurationList; 857 | buildConfigurations = ( 858 | 4CCCD8C81A8CEC7A00AB451F /* Debug */, 859 | 4CCCD8C91A8CEC7A00AB451F /* Release */, 860 | ); 861 | defaultConfigurationIsVisible = 0; 862 | defaultConfigurationName = Release; 863 | }; 864 | 4CCCD8CA1A8CEC7A00AB451F /* Build configuration list for PBXNativeTarget "TicTacToe" */ = { 865 | isa = XCConfigurationList; 866 | buildConfigurations = ( 867 | 4CCCD8CB1A8CEC7A00AB451F /* Debug */, 868 | 4CCCD8CC1A8CEC7A00AB451F /* Release */, 869 | ); 870 | defaultConfigurationIsVisible = 0; 871 | defaultConfigurationName = Release; 872 | }; 873 | 4CCCD8CD1A8CEC7A00AB451F /* Build configuration list for PBXNativeTarget "TicTacToeTests" */ = { 874 | isa = XCConfigurationList; 875 | buildConfigurations = ( 876 | 4CCCD8CE1A8CEC7A00AB451F /* Debug */, 877 | 4CCCD8CF1A8CEC7A00AB451F /* Release */, 878 | ); 879 | defaultConfigurationIsVisible = 0; 880 | defaultConfigurationName = Release; 881 | }; 882 | 4CE037BC1AA77A650046956E /* Build configuration list for PBXNativeTarget "TicTacToeKIFTests" */ = { 883 | isa = XCConfigurationList; 884 | buildConfigurations = ( 885 | 4CE037BD1AA77A650046956E /* Debug */, 886 | 4CE037BE1AA77A650046956E /* Release */, 887 | ); 888 | defaultConfigurationIsVisible = 0; 889 | defaultConfigurationName = Release; 890 | }; 891 | /* End XCConfigurationList section */ 892 | }; 893 | rootObject = 4CCCD89F1A8CEC7A00AB451F /* Project object */; 894 | } 895 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface AppDelegate : UIResponder 4 | 5 | @property (strong, nonatomic) UIWindow *window; 6 | 7 | 8 | @end 9 | 10 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import "HomePresenter.h" 4 | 5 | @implementation AppDelegate 6 | 7 | 8 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 9 | 10 | [self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]]; 11 | [[self window] makeKeyAndVisible]; 12 | 13 | UIViewController *viewController = [HomePresenter createViewController]; 14 | UINavigationController *navController = 15 | [[UINavigationController alloc] initWithRootViewController:viewController]; 16 | [[self window] setRootViewController:navController]; 17 | 18 | return YES; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/EndGameViewController.h: -------------------------------------------------------------------------------- 1 | #import "CHViewController.h" 2 | 3 | @class EndGameView; 4 | 5 | @interface EndGameViewController : CHViewController 6 | 7 | @property(nonatomic, readonly) EndGameView *endGameView; 8 | 9 | - (void)setGameOverStateText:(NSString *)text; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/EndGameViewController.m: -------------------------------------------------------------------------------- 1 | #import "EndGameViewController.h" 2 | 3 | #import "EndGameView.h" 4 | 5 | @interface EndGameViewController () 6 | 7 | @end 8 | 9 | @implementation EndGameViewController 10 | 11 | - (void)loadView { 12 | [self setView:[EndGameView new]]; 13 | } 14 | 15 | - (EndGameView *)endGameView { 16 | return (EndGameView *)[self view]; 17 | } 18 | 19 | - (void)setGameOverStateText:(NSString *)text { 20 | [[[self endGameView] gameStateLabel] setText:text]; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/GameViewController.h: -------------------------------------------------------------------------------- 1 | #import "CHViewController.h" 2 | 3 | #import "GameStates.h" 4 | 5 | @class GameView; 6 | @class TicTacToeBoard; 7 | 8 | FOUNDATION_EXPORT NSString *const kO; 9 | FOUNDATION_EXPORT NSString *const kX; 10 | FOUNDATION_EXPORT NSString *const kEmpty; 11 | 12 | @interface GameViewController : CHViewController 13 | 14 | @property(nonatomic, readonly) GameView *gameView; 15 | 16 | - (void)updateDisplayFromBoard:(TicTacToeBoard *)board; 17 | - (NSString *)valueForState:(TicTacToeStateType)state; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/GameViewController.m: -------------------------------------------------------------------------------- 1 | #import "GameViewController.h" 2 | 3 | #import "GameView.h" 4 | #import "TicTacToeBoard.h" 5 | 6 | @interface GameViewController () 7 | @end 8 | 9 | @implementation GameViewController 10 | 11 | NSString *const kO = @"O"; 12 | NSString *const kX = @"X"; 13 | NSString *const kEmpty = @""; 14 | 15 | - (void)loadView { 16 | [self setView:[GameView new]]; 17 | } 18 | 19 | - (GameView *)gameView { 20 | return (GameView *) [self view]; 21 | } 22 | 23 | - (void)updateDisplayFromBoard:(TicTacToeBoard *)board { 24 | for (int x = 0; x < 3; x++) { 25 | for (int y = 0; y < 3; y++) { 26 | NSString *value = [self valueForState:[board stateForXPos:x yPos:y]]; 27 | [[self gameView] updateValue:value atX:x y:y]; 28 | } 29 | } 30 | } 31 | 32 | - (NSString *)valueForState:(TicTacToeStateType)state { 33 | switch (state) { 34 | case TicTacToeStateO: 35 | return kO; 36 | case TicTacToeStateX: 37 | return kX; 38 | default: 39 | return kEmpty; 40 | } 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/infrastructure/CHPresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class CHViewController; 4 | 5 | @interface CHPresenter : NSObject 6 | 7 | @property(nonatomic, weak) CHViewController *viewController; 8 | 9 | - (void)viewLoaded; 10 | - (void)viewWillDisappear; 11 | - (NSArray *)leftNavigationButtons; 12 | - (NSArray *)rightNavigationButtons; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/infrastructure/CHPresenter.m: -------------------------------------------------------------------------------- 1 | #import "CHPresenter.h" 2 | 3 | @interface CHPresenter () { 4 | __weak CHViewController *viewController_; 5 | } 6 | 7 | @end 8 | 9 | @implementation CHPresenter 10 | 11 | @synthesize viewController = viewController_; 12 | 13 | - (void)viewLoaded { 14 | // By default, do nothing. 15 | } 16 | 17 | - (void)viewWillDisappear { 18 | // By default, do nothing. 19 | } 20 | 21 | - (NSArray *)leftNavigationButtons { 22 | return @[]; 23 | } 24 | 25 | - (NSArray *)rightNavigationButtons { 26 | return @[]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/infrastructure/CHViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class CHPresenter; 4 | 5 | @interface CHViewController : UIViewController 6 | 7 | @property(nonatomic, readonly) CHPresenter *presenter; 8 | 9 | // Designated initializer. 10 | - (id)initWithPresenter:(CHPresenter *)presenter; 11 | 12 | - (void)dismissViewControllerAnimated:(BOOL)animated 13 | withCompletionBlock:(void (^)(void))completionBlock; 14 | 15 | - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/infrastructure/CHViewController.m: -------------------------------------------------------------------------------- 1 | #import "CHViewController.h" 2 | 3 | #import "CHPresenter.h" 4 | 5 | @interface CHViewController() { 6 | CHPresenter *presenter_; 7 | } 8 | @end 9 | 10 | @implementation CHViewController 11 | 12 | @synthesize presenter = presenter_; 13 | 14 | - (id)initWithPresenter:(CHPresenter *)presenter { 15 | self = [super init]; 16 | if (self) { 17 | presenter_ = presenter; 18 | [presenter setViewController:self]; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | [[self navigationItem] setLeftBarButtonItems:[[self presenter] leftNavigationButtons] 27 | animated:YES]; 28 | [[self navigationItem] setRightBarButtonItems:[[self presenter] rightNavigationButtons] 29 | animated:YES]; 30 | [[self presenter] viewLoaded]; 31 | } 32 | 33 | - (void)viewWillDisappear:(BOOL)animated { 34 | [[self presenter] viewWillDisappear]; 35 | [super viewWillDisappear:animated]; 36 | } 37 | 38 | - (void)dismissViewControllerAnimated:(BOOL)animated 39 | withCompletionBlock:(void (^)(void))completionBlock { 40 | [[self navigationController] dismissViewControllerAnimated:animated 41 | completion:completionBlock]; 42 | } 43 | 44 | - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { 45 | [[self navigationController] pushViewController:viewController animated:animated]; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/model/ComputerPlayer.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "GameStates.h" 4 | 5 | @class TicTacToeBoard; 6 | 7 | @interface ComputerPlayer : NSObject 8 | 9 | // Designated initializer. 10 | - (id)initWithBoard:(TicTacToeBoard *)board type:(TicTacToeStateType)type; 11 | 12 | // Make the next move. 13 | - (void)makeNextMove; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/model/ComputerPlayer.m: -------------------------------------------------------------------------------- 1 | #import "ComputerPlayer.h" 2 | 3 | #import "TicTacToeBoard.h" 4 | 5 | @interface ComputerPlayer () { 6 | TicTacToeBoard *board_; 7 | TicTacToeStateType type_; 8 | } 9 | - (BOOL)complete3IfPossibleForType:(TicTacToeStateType)type; 10 | - (BOOL)completeColumnIfPossible:(int)row type:(TicTacToeStateType)type; 11 | - (BOOL)completeRowIfPossible:(int)row type:(TicTacToeStateType)type; 12 | - (BOOL)checkState:(TicTacToeStateType)state 13 | forSquareA:(TicTacToeStateType)sqA 14 | squareB:(TicTacToeStateType)sqB 15 | squareC:(TicTacToeStateType)sqC; 16 | - (void)playXPos:(int)x yPos:(int)y; 17 | @end 18 | 19 | @implementation ComputerPlayer 20 | 21 | - (id)initWithBoard:(TicTacToeBoard *)board type:(TicTacToeStateType)type { 22 | self = [super init]; 23 | if (self) { 24 | board_ = board; 25 | type_ = type; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)playXPos:(int)x yPos:(int)y { 31 | [board_ playXPos:x yPos:y toState:type_]; 32 | } 33 | 34 | - (void)makeNextMove { 35 | // Fill in to make 3 if possible. 36 | if ([self complete3IfPossibleForType:type_]) { 37 | return; 38 | } 39 | 40 | // Block 3 if possible. 41 | TicTacToeStateType userType = (type_ == TicTacToeStateO) ? TicTacToeStateX : TicTacToeStateO; 42 | if ([self complete3IfPossibleForType:userType]) { 43 | return; 44 | } 45 | 46 | // Just make the first available. 47 | for (int x = 0; x < 3; x++) { 48 | for (int y = 0; y < 3; y++) { 49 | if ([board_ stateForXPos:x yPos:y] == TicTacToeStateEmpty) { 50 | [self playXPos:x yPos:y]; 51 | return; 52 | } 53 | } 54 | } 55 | } 56 | 57 | - (BOOL)complete3IfPossibleForType:(TicTacToeStateType)type { 58 | for (int i = 0; i < 3; i++) { 59 | if ([self completeRowIfPossible:i type:type]) { 60 | return YES; 61 | } 62 | if ([self completeColumnIfPossible:i type:type]) { 63 | return YES; 64 | } 65 | } 66 | 67 | // Diagonal TL-BR. 68 | TicTacToeStateType sqA = [board_ stateForXPos:0 yPos:0]; 69 | TicTacToeStateType sqB = [board_ stateForXPos:1 yPos:1]; 70 | TicTacToeStateType sqC = [board_ stateForXPos:2 yPos:2]; 71 | 72 | if ([self checkState:type forSquareA:sqA squareB:sqB squareC:sqC]) { 73 | if (sqA == TicTacToeStateEmpty) { 74 | [self playXPos:0 yPos:0]; 75 | return YES; 76 | } 77 | if (sqB == TicTacToeStateEmpty) { 78 | [self playXPos:1 yPos:1]; 79 | return YES; 80 | } 81 | if (sqC == TicTacToeStateEmpty) { 82 | [self playXPos:2 yPos:2]; 83 | return YES; 84 | } 85 | } 86 | 87 | // Diagonal TR-BL. 88 | sqA = [board_ stateForXPos:0 yPos:2]; 89 | sqB = [board_ stateForXPos:1 yPos:1]; 90 | sqC = [board_ stateForXPos:2 yPos:0]; 91 | 92 | if ([self checkState:type forSquareA:sqA squareB:sqB squareC:sqC]) { 93 | if (sqA == TicTacToeStateEmpty) { 94 | [self playXPos:0 yPos:2]; 95 | return YES; 96 | } 97 | if (sqB == TicTacToeStateEmpty) { 98 | [self playXPos:1 yPos:1]; 99 | return YES; 100 | } 101 | if (sqC == TicTacToeStateEmpty) { 102 | [self playXPos:2 yPos:0]; 103 | return YES; 104 | } 105 | } 106 | 107 | return NO; 108 | } 109 | 110 | - (BOOL)completeColumnIfPossible:(int)column type:(TicTacToeStateType)type { 111 | TicTacToeStateType sqA = [board_ stateForXPos:0 yPos:column]; 112 | TicTacToeStateType sqB = [board_ stateForXPos:1 yPos:column]; 113 | TicTacToeStateType sqC = [board_ stateForXPos:2 yPos:column]; 114 | 115 | if ([self checkState:type forSquareA:sqA squareB:sqB squareC:sqC]) { 116 | if (sqA == TicTacToeStateEmpty) { 117 | [self playXPos:0 yPos:column]; 118 | return YES; 119 | } 120 | if (sqB == TicTacToeStateEmpty) { 121 | [self playXPos:1 yPos:column]; 122 | return YES; 123 | } 124 | if (sqC == TicTacToeStateEmpty) { 125 | [self playXPos:2 yPos:column]; 126 | return YES; 127 | } 128 | } 129 | return NO; 130 | } 131 | 132 | - (BOOL)completeRowIfPossible:(int)row type:(TicTacToeStateType)type { 133 | TicTacToeStateType sqA = [board_ stateForXPos:row yPos:0]; 134 | TicTacToeStateType sqB = [board_ stateForXPos:row yPos:1]; 135 | TicTacToeStateType sqC = [board_ stateForXPos:row yPos:2]; 136 | 137 | if ([self checkState:type forSquareA:sqA squareB:sqB squareC:sqC]) { 138 | if (sqA == TicTacToeStateEmpty) { 139 | [self playXPos:row yPos:0]; 140 | return YES; 141 | } 142 | if (sqB == TicTacToeStateEmpty) { 143 | [self playXPos:row yPos:1]; 144 | return YES; 145 | } 146 | if (sqC == TicTacToeStateEmpty) { 147 | [self playXPos:row yPos:2]; 148 | return YES; 149 | } 150 | } 151 | return NO; 152 | } 153 | 154 | - (BOOL)checkState:(TicTacToeStateType)state 155 | forSquareA:(TicTacToeStateType)sqA 156 | squareB:(TicTacToeStateType)sqB 157 | squareC:(TicTacToeStateType)sqC { 158 | int empty = 0; 159 | empty += (sqA == TicTacToeStateEmpty) ? 1 : 0; 160 | empty += (sqB == TicTacToeStateEmpty) ? 1 : 0; 161 | empty += (sqC == TicTacToeStateEmpty) ? 1 : 0; 162 | 163 | // One should be empty. 164 | if (empty != 1) { 165 | return NO; 166 | } 167 | 168 | int ofState = 0; 169 | ofState += (sqA == state) ? 1 : 0; 170 | ofState += (sqB == state) ? 1 : 0; 171 | ofState += (sqC == state) ? 1 : 0; 172 | 173 | // The other two should be the right type. 174 | return ofState == 2; 175 | } 176 | 177 | @end 178 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/model/GameStates.h: -------------------------------------------------------------------------------- 1 | #ifndef TicTacToe_GameStates_h 2 | #define TicTacToe_GameStates_h 3 | #endif 4 | 5 | typedef NS_ENUM(NSInteger, TicTacToeStateType) { 6 | TicTacToeStateX, 7 | TicTacToeStateO, 8 | TicTacToeStateEmpty, 9 | TicTacToeStateInvalid 10 | }; 11 | 12 | typedef NS_ENUM(NSInteger, TicTacToeGameStateType) { 13 | TicTacToeGameStateNotEnded, 14 | TicTacToeGameStateBoardFull, 15 | TicTacToeGameStateXWin, 16 | TicTacToeGameStateOWin, 17 | }; 18 | 19 | typedef NS_ENUM(NSInteger, TicTacToeGameType) { 20 | TicTacToeGameUserX, 21 | TicTacToeGameUserO, 22 | TicTacToeGameUserXO 23 | }; 24 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/model/TicTacToeBoard.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "GameStates.h" 4 | 5 | @interface TicTacToeBoard : NSObject 6 | 7 | // Returns the state of the game: not ended, O wins, X wins, or tie. 8 | @property(nonatomic, readonly) TicTacToeGameStateType gameState; 9 | 10 | // Returns the state of the square at the given position on the board. 11 | // Invalid positions will return TicTacToeStateInvalid. 12 | - (TicTacToeStateType)stateForXPos:(NSInteger)x yPos:(NSInteger)y; 13 | 14 | // Attempts to play in the position (x,y). Returns YES for success, NO if not. 15 | - (BOOL)playXPos:(NSInteger)x 16 | yPos:(NSInteger)y 17 | toState:(TicTacToeStateType)state; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/model/TicTacToeBoard.m: -------------------------------------------------------------------------------- 1 | #import "TicTacToeBoard.h" 2 | 3 | /* 4 | The board is: 5 | 0,0 | 0,1 | 0,2 6 | 1,0 | 1,1 | 1,2 7 | 2,0 | 2,1 | 2,2 8 | */ 9 | @interface TicTacToeBoard () { 10 | NSMutableArray *board_; 11 | } 12 | @end 13 | 14 | @implementation TicTacToeBoard 15 | 16 | - (id)init { 17 | self = [super init]; 18 | if (self) { 19 | NSNumber *v = [NSNumber numberWithInteger:TicTacToeStateEmpty]; 20 | NSMutableArray *vs = [NSMutableArray arrayWithArray:@[v, v, v]]; 21 | board_ = 22 | [NSMutableArray arrayWithArray:@[[vs mutableCopy], [vs mutableCopy], [vs mutableCopy]]]; 23 | } 24 | return self; 25 | } 26 | 27 | - (TicTacToeGameStateType)gameState { 28 | for (int i = 0; i < 3; i++) { 29 | if (board_[i][0] == board_[i][1] && board_[i][1] == board_[i][2]) { 30 | if ([board_[i][0] integerValue] == TicTacToeStateO) { 31 | return TicTacToeGameStateOWin; 32 | } else if ([board_[i][0] integerValue] == TicTacToeStateX) { 33 | return TicTacToeGameStateXWin; 34 | } 35 | } 36 | if (board_[0][i] == board_[1][i] && board_[1][i] == board_[2][i]) { 37 | if ([board_[0][i] integerValue] == TicTacToeStateO) { 38 | return TicTacToeGameStateOWin; 39 | } else if ([board_[0][i] integerValue] == TicTacToeStateX) { 40 | return TicTacToeGameStateXWin; 41 | } 42 | } 43 | } 44 | if (board_[0][0] == board_[1][1] && board_[1][1] == board_[2][2]) { 45 | if ([board_[0][0] integerValue] == TicTacToeStateO) { 46 | return TicTacToeGameStateOWin; 47 | } else if ([board_[0][0] integerValue] == TicTacToeStateX) { 48 | return TicTacToeGameStateXWin; 49 | } 50 | } 51 | if (board_[0][2] == board_[1][1] && board_[1][1] == board_[2][0]) { 52 | if ([board_[0][2] integerValue] == TicTacToeStateO) { 53 | return TicTacToeGameStateOWin; 54 | } else if ([board_[0][2] integerValue] == TicTacToeStateX) { 55 | return TicTacToeGameStateXWin; 56 | } 57 | } 58 | for (int x = 0; x < 3; x++) { 59 | for (int y = 0; y < 3; y++) { 60 | if ([board_[x][y] integerValue] == TicTacToeStateEmpty) { 61 | return TicTacToeGameStateNotEnded; 62 | } 63 | } 64 | } 65 | return TicTacToeGameStateBoardFull; 66 | } 67 | 68 | - (TicTacToeStateType)stateForXPos:(NSInteger)x yPos:(NSInteger)y { 69 | if (x < 0 || x > 2 || y < 0 || y > 2) { 70 | return TicTacToeStateInvalid; 71 | } else { 72 | return [board_[x][y] integerValue]; 73 | } 74 | } 75 | 76 | - (BOOL)playXPos:(NSInteger)x yPos:(NSInteger)y toState:(TicTacToeStateType)state { 77 | if (x < 0 || x > 2 || y < 0 || y > 2 || 78 | state == TicTacToeStateEmpty || state == TicTacToeStateInvalid || 79 | [board_[x][y] integerValue] != TicTacToeStateEmpty) { 80 | return NO; 81 | } 82 | board_[x][y] = [NSNumber numberWithInteger:state]; 83 | return YES; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/presenters/EndGamePresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "GameStates.h" 4 | #import "CHPresenter.h" 5 | 6 | FOUNDATION_EXPORT NSString *const kOWin; 7 | FOUNDATION_EXPORT NSString *const kXWin; 8 | FOUNDATION_EXPORT NSString *const kTie; 9 | 10 | @interface EndGamePresenter : CHPresenter 11 | 12 | + (UIViewController *)createViewControllerWithEndGameState:(TicTacToeGameStateType)gameState; 13 | 14 | // Designated initializer. Exposed for testing. 15 | - (id)initWithEndGameState:(TicTacToeGameStateType)gameState; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/presenters/EndGamePresenter.m: -------------------------------------------------------------------------------- 1 | #import "EndGamePresenter.h" 2 | 3 | #import "EndGameView.h" 4 | #import "EndGameViewController.h" 5 | #import "HomePresenter.h" 6 | 7 | @interface EndGamePresenter () { 8 | TicTacToeGameStateType gameState_; 9 | } 10 | @property(nonatomic, readonly) EndGameViewController *endGameViewController; 11 | 12 | - (void)playAgainButtonPressed:(id)sender; 13 | @end 14 | 15 | @implementation EndGamePresenter 16 | 17 | NSString *const kOWin = @"O wins"; 18 | NSString *const kXWin = @"X wins"; 19 | NSString *const kTie = @"Tie"; 20 | 21 | + (UIViewController *)createViewControllerWithEndGameState:(TicTacToeGameStateType)gameState { 22 | return [[EndGameViewController alloc] initWithPresenter: 23 | [[EndGamePresenter alloc] initWithEndGameState:gameState]]; 24 | } 25 | 26 | - (id)initWithEndGameState:(TicTacToeGameStateType)gameState { 27 | self = [super init]; 28 | if (self) { 29 | gameState_ = gameState; 30 | } 31 | return self; 32 | } 33 | 34 | - (EndGameViewController *)endGameViewController { 35 | return (EndGameViewController *) [self viewController]; 36 | } 37 | 38 | - (void)viewLoaded { 39 | EndGameViewController *vc = [self endGameViewController]; 40 | 41 | NSString *text; 42 | switch (gameState_) { 43 | case TicTacToeGameStateOWin: 44 | text = kOWin; 45 | break; 46 | case TicTacToeGameStateXWin: 47 | text = kXWin; 48 | break; 49 | case TicTacToeGameStateBoardFull: 50 | text = kTie; 51 | default: 52 | break; 53 | } 54 | [vc setGameOverStateText:text]; 55 | 56 | [[[vc endGameView] playAgainButton] addTarget:self 57 | action:@selector(playAgainButtonPressed:) 58 | forControlEvents:UIControlEventTouchUpInside]; 59 | } 60 | 61 | - (void)playAgainButtonPressed:(id)sender { 62 | UIViewController *homeViewController = [HomePresenter createViewController]; 63 | UINavigationController *navController = 64 | [[UINavigationController alloc] initWithRootViewController:homeViewController]; 65 | [[self viewController] presentViewController:navController animated:YES completion:nil]; 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/presenters/GamePresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "GameStates.h" 4 | #import "CHPresenter.h" 5 | 6 | @class ComputerPlayer; 7 | @class GameViewController; 8 | @class TicTacToeBoard; 9 | 10 | @interface GamePresenter : CHPresenter 11 | 12 | @property(nonatomic, readonly) TicTacToeGameType gameType; 13 | 14 | + (UIViewController *)createViewControllerWithGameType:(TicTacToeGameType)gameType; 15 | 16 | // Designated initializer. Exposed for testing. 17 | - (id)initWithBoard:(TicTacToeBoard *)board 18 | computerPlayer:(ComputerPlayer *)computerPlayer 19 | gameType:(TicTacToeGameType)gameType; 20 | 21 | // Visible for testing. 22 | @property(nonatomic, assign) BOOL computerInPlay; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/presenters/GamePresenter.m: -------------------------------------------------------------------------------- 1 | #import "GamePresenter.h" 2 | 3 | #import "ComputerPlayer.h" 4 | #import "EndGamePresenter.h" 5 | #import "GameView.h" 6 | #import "GameViewController.h" 7 | #import "TicTacToeBoard.h" 8 | #import "TicTacToeButton.h" 9 | 10 | @interface GamePresenter () { 11 | TicTacToeBoard *board_; 12 | BOOL computerInPlay_; 13 | ComputerPlayer *computerPlayer_; 14 | TicTacToeGameType gameType_; 15 | TicTacToeStateType turn_; 16 | } 17 | 18 | @property(nonatomic, readonly) GameViewController *gameViewController; 19 | 20 | - (void)buttonPressed:(id)sender; 21 | - (void)gameOverWithState:(TicTacToeGameStateType)state; 22 | - (void)handleEndOfTurn; 23 | - (void)handlePossibleGameEnd; 24 | - (void)maybePlayComputerTurn; 25 | - (void)playComputerTurn; 26 | - (void)updateTurn; 27 | @end 28 | 29 | @implementation GamePresenter 30 | 31 | @synthesize computerInPlay = computerInPlay_; 32 | @synthesize gameType = gameType_; 33 | 34 | static const NSTimeInterval kComputerPlayDelay = 1; 35 | 36 | + (UIViewController *)createViewControllerWithGameType:(TicTacToeGameType)gameType { 37 | TicTacToeBoard *board = [TicTacToeBoard new]; 38 | TicTacToeStateType type = (gameType == TicTacToeGameUserO) ? TicTacToeStateX : TicTacToeStateO; 39 | ComputerPlayer *computerPlayer = [[ComputerPlayer alloc] initWithBoard:board type:type]; 40 | GamePresenter *presenter = [[GamePresenter alloc] initWithBoard:board 41 | computerPlayer:computerPlayer 42 | gameType:gameType]; 43 | return [[GameViewController alloc] initWithPresenter:presenter]; 44 | } 45 | 46 | - (id)initWithBoard:(TicTacToeBoard *)board 47 | computerPlayer:(ComputerPlayer *)computerPlayer 48 | gameType:(TicTacToeGameType)gameType { 49 | self = [super init]; 50 | if (self) { 51 | board_ = board; 52 | computerInPlay_ = NO; 53 | computerPlayer_ = computerPlayer; 54 | gameType_ = gameType; 55 | turn_ = TicTacToeStateO; 56 | } 57 | return self; 58 | } 59 | 60 | - (GameViewController *)gameViewController { 61 | return (GameViewController *) [self viewController]; 62 | } 63 | 64 | - (void)viewLoaded { 65 | for (TicTacToeButton *button in [[[self gameViewController] gameView] buttons]) { 66 | [button addTarget:self 67 | action:@selector(buttonPressed:) 68 | forControlEvents:UIControlEventTouchUpInside]; 69 | } 70 | 71 | [self maybePlayComputerTurn]; 72 | } 73 | 74 | - (void)buttonPressed:(id)sender { 75 | // Ignore if computer is in play. 76 | if (computerInPlay_) { 77 | return; 78 | } 79 | TicTacToeButton *button = (TicTacToeButton *)sender; 80 | // Play 81 | NSInteger x = [button x]; 82 | NSInteger y = [button y]; 83 | if ([board_ playXPos:x yPos:y toState:turn_]) { 84 | [self handleEndOfTurn]; 85 | [self maybePlayComputerTurn]; 86 | } 87 | } 88 | 89 | - (void)gameOverWithState:(TicTacToeGameStateType)state { 90 | UIViewController *viewController = 91 | [EndGamePresenter createViewControllerWithEndGameState:state]; 92 | [[self viewController] pushViewController:viewController animated:YES]; 93 | } 94 | 95 | - (void)handleEndOfTurn { 96 | // Change turn. 97 | [self updateTurn]; 98 | [[self gameViewController] updateDisplayFromBoard:board_]; 99 | [self handlePossibleGameEnd]; 100 | } 101 | 102 | - (void)handlePossibleGameEnd { 103 | TicTacToeGameStateType gameState = [board_ gameState]; 104 | if (gameState != TicTacToeGameStateNotEnded) { 105 | [self gameOverWithState:gameState]; 106 | } 107 | } 108 | 109 | - (void)maybePlayComputerTurn { 110 | if (gameType_ == TicTacToeGameUserXO || 111 | (gameType_ == TicTacToeGameUserO && turn_ == TicTacToeStateO) || 112 | (gameType_ == TicTacToeGameUserX && turn_ == TicTacToeStateX) || 113 | [board_ gameState] != TicTacToeGameStateNotEnded) { 114 | return; 115 | } 116 | 117 | computerInPlay_ = YES; 118 | [self performSelector:@selector(playComputerTurn) withObject:nil afterDelay:kComputerPlayDelay]; 119 | } 120 | 121 | - (void)playComputerTurn { 122 | [computerPlayer_ makeNextMove]; 123 | [self handleEndOfTurn]; 124 | computerInPlay_ = NO; 125 | } 126 | 127 | - (void)updateTurn { 128 | turn_ = (turn_ == TicTacToeStateO) ? TicTacToeStateX : TicTacToeStateO; 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/presenters/HomePresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "CHPresenter.h" 4 | 5 | @class HomeViewController; 6 | 7 | @interface HomePresenter : CHPresenter 8 | 9 | + (UIViewController *)createViewController; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/presenters/HomePresenter.m: -------------------------------------------------------------------------------- 1 | #import "HomePresenter.h" 2 | 3 | #import "GamePresenter.h" 4 | #import "HomeView.h" 5 | #import "HomeViewController.h" 6 | 7 | @interface HomePresenter () 8 | @property(nonatomic, readonly) HomeViewController *homeViewController; 9 | 10 | - (void)pushGameViewControllerWithGameType:(TicTacToeGameType)gameType; 11 | - (void)oButtonPressed:(id)sender; 12 | - (void)xButtonPressed:(id)sender; 13 | - (void)xoButtonPressed:(id)sender; 14 | @end 15 | 16 | @implementation HomePresenter 17 | 18 | + (UIViewController *)createViewController { 19 | return [[HomeViewController alloc] initWithPresenter:[HomePresenter new]]; 20 | } 21 | 22 | - (HomeViewController *)homeViewController { 23 | return (HomeViewController *) [self viewController]; 24 | } 25 | 26 | - (void)viewLoaded { 27 | HomeView *view = [[self homeViewController] homeView]; 28 | 29 | [[view playOButton] addTarget:self 30 | action:@selector(oButtonPressed:) 31 | forControlEvents:UIControlEventTouchUpInside]; 32 | [[view playXButton] addTarget:self 33 | action:@selector(xButtonPressed:) 34 | forControlEvents:UIControlEventTouchUpInside]; 35 | [[view playXOButton] addTarget:self 36 | action:@selector(xoButtonPressed:) 37 | forControlEvents:UIControlEventTouchUpInside]; 38 | 39 | } 40 | 41 | - (void)oButtonPressed:(id)sender { 42 | [self pushGameViewControllerWithGameType:TicTacToeGameUserO]; 43 | } 44 | 45 | - (void)xButtonPressed:(id)sender { 46 | [self pushGameViewControllerWithGameType:TicTacToeGameUserX]; 47 | } 48 | 49 | - (void)xoButtonPressed:(id)sender { 50 | [self pushGameViewControllerWithGameType:TicTacToeGameUserXO]; 51 | } 52 | 53 | - (void)pushGameViewControllerWithGameType:(TicTacToeGameType)gameType { 54 | UIViewController *viewController = [GamePresenter createViewControllerWithGameType:gameType]; 55 | [[self viewController] pushViewController:viewController animated:YES]; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/viewcontrollers/HomeViewController.h: -------------------------------------------------------------------------------- 1 | #import "CHViewController.h" 2 | 3 | @class HomeView; 4 | 5 | @interface HomeViewController : CHViewController 6 | 7 | @property(nonatomic, readonly) HomeView *homeView; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/viewcontrollers/HomeViewController.m: -------------------------------------------------------------------------------- 1 | #import "HomeViewController.h" 2 | 3 | #import "HomeView.h" 4 | 5 | @implementation HomeViewController 6 | 7 | - (void)loadView { 8 | [self setView:[HomeView new]]; 9 | } 10 | 11 | - (HomeView *)homeView { 12 | return (HomeView *)[self view]; 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/EndGameView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EndGameView : UIView 4 | 5 | @property(nonatomic, readonly) UILabel *gameStateLabel; 6 | @property(nonatomic, readonly) UIButton *playAgainButton; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/EndGameView.m: -------------------------------------------------------------------------------- 1 | #import "EndGameView.h" 2 | 3 | @interface EndGameView () { 4 | UILabel *gameStateLabel_; 5 | UIButton *playAgainButton_; 6 | } 7 | 8 | - (void)createView; 9 | - (void)setUpConstraints; 10 | 11 | @end 12 | 13 | @implementation EndGameView 14 | 15 | static const CGFloat kLabelPadding = 25.0; 16 | static const CGFloat kPadding = 5.0; 17 | static const CGFloat kMaxButtonHeight = 40; 18 | 19 | @synthesize gameStateLabel = gameStateLabel_; 20 | @synthesize playAgainButton = playAgainButton_; 21 | 22 | - (id)initWithFrame:(CGRect)frame { 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | [self createView]; 26 | [self setUpConstraints]; 27 | } 28 | return self; 29 | } 30 | 31 | - (void)createView { 32 | [self setBackgroundColor:[UIColor grayColor]]; 33 | 34 | gameStateLabel_ = [UILabel new]; 35 | [[self gameStateLabel] setTranslatesAutoresizingMaskIntoConstraints:NO]; 36 | [[self gameStateLabel] setTextAlignment:NSTextAlignmentCenter]; 37 | [[self gameStateLabel] setFont:[UIFont systemFontOfSize:18]]; 38 | [[self gameStateLabel] setTextColor:[UIColor whiteColor]]; 39 | [self addSubview:[self gameStateLabel]]; 40 | 41 | playAgainButton_ = [UIButton new]; 42 | [[self playAgainButton] setTitle:@"play again" forState:UIControlStateNormal]; 43 | [[self playAgainButton] setTranslatesAutoresizingMaskIntoConstraints:NO]; 44 | [self addSubview:[self playAgainButton]]; 45 | } 46 | 47 | - (void)setUpConstraints { 48 | [[NSLayoutConstraint constraintWithItem:[self gameStateLabel] 49 | attribute:NSLayoutAttributeCenterX 50 | relatedBy:NSLayoutRelationEqual 51 | toItem:self 52 | attribute:NSLayoutAttributeCenterX 53 | multiplier:1 54 | constant:0] setActive:YES]; 55 | [[NSLayoutConstraint constraintWithItem:[self gameStateLabel] 56 | attribute:NSLayoutAttributeWidth 57 | relatedBy:NSLayoutRelationEqual 58 | toItem:self 59 | attribute:NSLayoutAttributeWidth 60 | multiplier:1 61 | constant:-(2 * kLabelPadding)] setActive:YES]; 62 | [[NSLayoutConstraint constraintWithItem:[self gameStateLabel] 63 | attribute:NSLayoutAttributeCenterY 64 | relatedBy:NSLayoutRelationEqual 65 | toItem:self 66 | attribute:NSLayoutAttributeCenterY 67 | multiplier:0.5 68 | constant:0] setActive:YES]; 69 | [[NSLayoutConstraint constraintWithItem:[self gameStateLabel] 70 | attribute:NSLayoutAttributeHeight 71 | relatedBy:NSLayoutRelationEqual 72 | toItem:self 73 | attribute:NSLayoutAttributeHeight 74 | multiplier:0.3 75 | constant:0] setActive:YES]; 76 | 77 | [[NSLayoutConstraint constraintWithItem:[self playAgainButton] 78 | attribute:NSLayoutAttributeBottom 79 | relatedBy:NSLayoutRelationEqual 80 | toItem:self 81 | attribute:NSLayoutAttributeBottom 82 | multiplier:1 83 | constant:-kPadding] setActive:YES]; 84 | [[NSLayoutConstraint constraintWithItem:[self playAgainButton] 85 | attribute:NSLayoutAttributeWidth 86 | relatedBy:NSLayoutRelationEqual 87 | toItem:self 88 | attribute:NSLayoutAttributeWidth 89 | multiplier:1 90 | constant:(2 * -kPadding)] setActive:YES]; 91 | [[NSLayoutConstraint constraintWithItem:[self playAgainButton] 92 | attribute:NSLayoutAttributeCenterX 93 | relatedBy:NSLayoutRelationEqual 94 | toItem:self 95 | attribute:NSLayoutAttributeCenterX 96 | multiplier:1 97 | constant:0] setActive:YES]; 98 | [[NSLayoutConstraint constraintWithItem:[self playAgainButton] 99 | attribute:NSLayoutAttributeHeight 100 | relatedBy:NSLayoutRelationLessThanOrEqual 101 | toItem:nil 102 | attribute:NSLayoutAttributeNotAnAttribute 103 | multiplier:1 104 | constant:kMaxButtonHeight] setActive:YES]; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/GameView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "GameStates.h" 4 | 5 | @class TicTacToeButton; 6 | 7 | @interface GameView : UIView 8 | 9 | @property(nonatomic, readonly) NSArray *buttons; 10 | 11 | - (void)updateValue:(NSString *)value atX :(int)x y:(int)y; 12 | 13 | // Visible for unit testing. 14 | - (TicTacToeButton *)buttonAtX:(int)x y:(int)y; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/GameView.m: -------------------------------------------------------------------------------- 1 | #import "GameView.h" 2 | 3 | #import "TicTacToeButton.h" 4 | 5 | @interface GameView () { 6 | NSArray *buttons_; 7 | } 8 | 9 | - (TicTacToeButton *)createAndAddButtonAtX:(NSInteger)x y:(NSInteger)y; 10 | - (void)createView; 11 | - (void)setUpConstraints; 12 | @end 13 | 14 | @implementation GameView 15 | 16 | static const CGFloat kPadding = 5.0; 17 | 18 | - (id)initWithFrame:(CGRect)frame { 19 | self = [super initWithFrame:frame]; 20 | if (self) { 21 | [self createView]; 22 | [self setUpConstraints]; 23 | } 24 | return self; 25 | } 26 | 27 | - (void)createView { 28 | [self setBackgroundColor:[UIColor blackColor]]; 29 | 30 | buttons_ = [@[[NSMutableArray arrayWithCapacity:3], 31 | [NSMutableArray arrayWithCapacity:3], 32 | [NSMutableArray arrayWithCapacity:3]] mutableCopy]; 33 | 34 | buttons_[0][0] = [self createAndAddButtonAtX:0 y:0]; 35 | buttons_[0][1] = [self createAndAddButtonAtX:1 y:0]; 36 | buttons_[0][2] = [self createAndAddButtonAtX:2 y:0]; 37 | buttons_[1][0] = [self createAndAddButtonAtX:0 y:1]; 38 | buttons_[1][1] = [self createAndAddButtonAtX:1 y:1]; 39 | buttons_[1][2] = [self createAndAddButtonAtX:2 y:1]; 40 | buttons_[2][0] = [self createAndAddButtonAtX:0 y:2]; 41 | buttons_[2][1] = [self createAndAddButtonAtX:1 y:2]; 42 | buttons_[2][2] = [self createAndAddButtonAtX:2 y:2]; 43 | } 44 | 45 | - (void)setUpConstraints { 46 | NSDictionary *views = @{ 47 | @"a": [self buttonAtX:0 y:0], 48 | @"b": [self buttonAtX:1 y:0], 49 | @"c": [self buttonAtX:2 y:0] 50 | }; 51 | 52 | NSString *format = @"|-(padding)-[a]-(padding)-[b(==a)]-(padding)-[c(==a)]-(padding)-|"; 53 | NSLayoutFormatOptions option = NSLayoutFormatAlignAllBottom | NSLayoutFormatAlignAllTop; 54 | NSDictionary *metrics = @{@"padding": @(kPadding)}; 55 | NSMutableArray *hConstraints = 56 | [[NSLayoutConstraint constraintsWithVisualFormat:format 57 | options:option 58 | metrics:metrics 59 | views:views] mutableCopy]; 60 | 61 | views = @{ 62 | @"d": [self buttonAtX:0 y:1], 63 | @"e": [self buttonAtX:1 y:1], 64 | @"f": [self buttonAtX:2 y:1] 65 | }; 66 | format = @"|-(padding)-[d]-(padding)-[e(==d)]-(padding)-[f(==d)]-(padding)-|"; 67 | [hConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:format 68 | options:option 69 | metrics:metrics 70 | views:views]]; 71 | views = @{ 72 | @"g": [self buttonAtX:0 y:2], 73 | @"h": [self buttonAtX:1 y:2], 74 | @"i": [self buttonAtX:2 y:2] 75 | }; 76 | format = @"|-(padding)-[g]-(padding)-[h(==g)]-(padding)-[i(==g)]-(padding)-|"; 77 | [hConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:format 78 | options:option 79 | metrics:metrics 80 | views:views]]; 81 | [NSLayoutConstraint activateConstraints:hConstraints]; 82 | 83 | 84 | views = @{ 85 | @"a": [self buttonAtX:0 y:0], 86 | @"d": [self buttonAtX:0 y:1], 87 | @"g": [self buttonAtX:0 y:2] 88 | }; 89 | format = @"V:[a]-(padding)-[d(==a)]-(padding)-[g(==a)]"; 90 | option = NSLayoutFormatAlignAllLeft | NSLayoutFormatAlignAllRight; 91 | NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat:format 92 | options:option 93 | metrics:metrics 94 | views:views]; 95 | [NSLayoutConstraint activateConstraints:vConstraints]; 96 | 97 | [[NSLayoutConstraint constraintWithItem:[self buttonAtX:0 y:0] 98 | attribute:NSLayoutAttributeHeight 99 | relatedBy:NSLayoutRelationEqual 100 | toItem:[self buttonAtX:0 y:0] 101 | attribute:NSLayoutAttributeWidth 102 | multiplier:1 103 | constant:0] setActive:YES]; 104 | 105 | [[NSLayoutConstraint constraintWithItem:[self buttonAtX:1 y:1] 106 | attribute:NSLayoutAttributeCenterY 107 | relatedBy:NSLayoutRelationEqual 108 | toItem:self 109 | attribute:NSLayoutAttributeCenterY 110 | multiplier:1 111 | constant:0] setActive:YES]; 112 | } 113 | 114 | - (TicTacToeButton *)createAndAddButtonAtX:(NSInteger)x y:(NSInteger)y { 115 | TicTacToeButton *button = [[TicTacToeButton alloc] initWithX:x y:y]; 116 | [button setTranslatesAutoresizingMaskIntoConstraints:NO]; 117 | [button setBackgroundColor:[UIColor lightGrayColor]]; 118 | [self addSubview:button]; 119 | return button; 120 | } 121 | 122 | #pragma mark getters 123 | 124 | - (TicTacToeButton *)buttonAtX:(int)x y:(int)y { 125 | return buttons_[y][x]; 126 | } 127 | 128 | - (NSArray *)buttons { 129 | return @[[self buttonAtX:0 y:0], [self buttonAtX:1 y:0], [self buttonAtX:2 y:0], 130 | [self buttonAtX:0 y:1], [self buttonAtX:1 y:1], [self buttonAtX:2 y:1], 131 | [self buttonAtX:0 y:2], [self buttonAtX:1 y:2], [self buttonAtX:2 y:2]]; 132 | } 133 | 134 | #pragma mark update state 135 | 136 | - (void)updateValue:(NSString *)value atX :(int)x y:(int)y { 137 | [[self buttonAtX:x y:y] setTitle:value forState:UIControlStateNormal]; 138 | } 139 | 140 | @end 141 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/HomeView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface HomeView : UIView 4 | 5 | @property(nonatomic, readonly) UIButton *playOButton; 6 | @property(nonatomic, readonly) UIButton *playXButton; 7 | @property(nonatomic, readonly) UIButton *playXOButton; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/HomeView.m: -------------------------------------------------------------------------------- 1 | #import "HomeView.h" 2 | 3 | @interface HomeView () { 4 | UIButton *playXOButton_; 5 | UIButton *playXButton_; 6 | UIButton *playOButton_; 7 | } 8 | 9 | - (void)createView; 10 | - (void)setUpConstraints; 11 | 12 | @end 13 | 14 | @implementation HomeView 15 | 16 | @synthesize playOButton = playOButton_; 17 | @synthesize playXButton = playXButton_; 18 | @synthesize playXOButton = playXOButton_; 19 | 20 | static const CGFloat kPadding = 5.0; 21 | 22 | - (id)initWithFrame:(CGRect)frame { 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | [self createView]; 26 | [self setUpConstraints]; 27 | } 28 | return self; 29 | } 30 | 31 | - (void)createView { 32 | [self setBackgroundColor:[UIColor whiteColor]]; 33 | 34 | playXOButton_ = [UIButton new]; 35 | [[self playXOButton] setTitle:@"XO" forState:UIControlStateNormal]; 36 | [[self playXOButton] setTranslatesAutoresizingMaskIntoConstraints:NO]; 37 | [[self playXOButton] setBackgroundColor:[UIColor purpleColor]]; 38 | [self addSubview:[self playXOButton]]; 39 | 40 | playOButton_ = [UIButton new]; 41 | [[self playOButton] setTitle:@"O" forState:UIControlStateNormal]; 42 | [[self playOButton] setTranslatesAutoresizingMaskIntoConstraints:NO]; 43 | [[self playOButton] setBackgroundColor:[UIColor magentaColor]]; 44 | [self addSubview:[self playOButton]]; 45 | 46 | playXButton_ = [UIButton new]; 47 | [[self playXButton] setTitle:@"X" forState:UIControlStateNormal]; 48 | [[self playXButton] setTranslatesAutoresizingMaskIntoConstraints:NO]; 49 | [[self playXButton] setBackgroundColor:[UIColor blueColor]]; 50 | [self addSubview:[self playXButton]]; 51 | } 52 | 53 | - (void)setUpConstraints { 54 | NSDictionary *views = @{ 55 | @"xo": [self playXOButton], 56 | @"x": [self playXButton], 57 | @"o": [self playOButton] 58 | }; 59 | 60 | NSString *format = @"|-(padding)-[xo]-(padding)-[x(==xo)]-(padding)-[o(==xo)]-(padding)-|"; 61 | NSLayoutFormatOptions option = NSLayoutFormatAlignAllBottom | NSLayoutFormatAlignAllTop; 62 | NSDictionary *metrics = @{@"padding": @(kPadding)}; 63 | NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:format 64 | options:option 65 | metrics:metrics 66 | views:views]; 67 | [NSLayoutConstraint activateConstraints:hConstraints]; 68 | 69 | NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[xo]-(padding)-|" 70 | options:0 71 | metrics:metrics 72 | views:views]; 73 | [NSLayoutConstraint activateConstraints:vConstraints]; 74 | 75 | [[NSLayoutConstraint constraintWithItem:[self playXOButton] 76 | attribute:NSLayoutAttributeHeight 77 | relatedBy:NSLayoutRelationEqual 78 | toItem:[self playXOButton] 79 | attribute:NSLayoutAttributeWidth 80 | multiplier:1 81 | constant:0] setActive:YES]; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/TicTacToeButton.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TicTacToeButton : UIButton 4 | 5 | @property(nonatomic, readonly) NSInteger x; 6 | @property(nonatomic, readonly) NSInteger y; 7 | 8 | - (id)initWithX:(NSInteger)x y:(NSInteger)y; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Classes/views/TicTacToeButton.m: -------------------------------------------------------------------------------- 1 | #import "TicTacToeButton.h" 2 | 3 | @interface TicTacToeButton () { 4 | NSInteger x_; 5 | NSInteger y_; 6 | } 7 | @end 8 | 9 | @implementation TicTacToeButton 10 | 11 | @synthesize x = x_; 12 | @synthesize y = y_; 13 | 14 | - (id)initWithX:(NSInteger)x y:(NSInteger)y { 15 | self = [super init]; 16 | if (self) { 17 | x_ = x; 18 | y_ = y; 19 | [self setAccessibilityLabel:[NSString stringWithFormat:@"%ld,%ld", (long)x, (long)y]]; 20 | } 21 | return self; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | catehuston.com.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToe/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AppDelegate.h" 3 | 4 | int main(int argc, char * argv[]) { 5 | @autoreleasepool { 6 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeKIFTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | catehuston.com.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeKIFTests/TicTacToeTests.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TicTacToeTests : KIFTestCase 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeKIFTests/TicTacToeTests.m: -------------------------------------------------------------------------------- 1 | #import "TicTacToeTests.h" 2 | 3 | @implementation TicTacToeTests 4 | 5 | - (void)testLoadHomeScreenTapO { 6 | [tester waitForViewWithAccessibilityLabel:@"O"]; 7 | [tester tapViewWithAccessibilityLabel:@"O"]; 8 | [tester tapViewWithAccessibilityLabel:@"1,1"]; 9 | [tester tapViewWithAccessibilityLabel:@"Back"]; 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | catehuston.com.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/infrastructure/CHPresenterTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "CHPresenter.h" 6 | #import "CHViewController.h" 7 | 8 | @interface CHPresenterTest : XCTestCase { 9 | id mockViewController_; 10 | CHPresenter *presenter_; 11 | } 12 | 13 | @end 14 | 15 | @implementation CHPresenterTest 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | mockViewController_ = OCMStrictClassMock([CHViewController class]); 21 | presenter_ = [[CHPresenter alloc] init]; 22 | [presenter_ setViewController:mockViewController_]; 23 | } 24 | 25 | - (void)tearDown { 26 | OCMVerifyAll(mockViewController_); 27 | [super tearDown]; 28 | } 29 | 30 | - (void)testViewLoaded { 31 | // By default, do nothing. 32 | [presenter_ viewLoaded]; 33 | } 34 | 35 | - (void)testViewWillDisappear { 36 | // By default, do nothing. 37 | [presenter_ viewWillDisappear]; 38 | } 39 | 40 | - (void)testLeftNavigationButtons { 41 | // By default, empty. 42 | XCTAssertEqual(0, [[presenter_ leftNavigationButtons] count]); 43 | } 44 | 45 | - (void)testRightNavigationButtons { 46 | // By default, empty. 47 | XCTAssertEqual(0, [[presenter_ rightNavigationButtons] count]); 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/infrastructure/CHViewControllerTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "CHPresenter.h" 6 | #import "CHViewController.h" 7 | 8 | @interface CHViewControllerTest : XCTestCase { 9 | id mockPresenter_; 10 | id mockNavigationController_; 11 | id mockViewController_; 12 | CHViewController *viewController_; 13 | } 14 | @end 15 | 16 | @implementation CHViewControllerTest 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | 21 | mockNavigationController_ = OCMStrictClassMock([UINavigationController class]); 22 | mockPresenter_ = OCMStrictClassMock([CHPresenter class]); 23 | OCMExpect([mockPresenter_ setViewController:OCMOCK_ANY]); 24 | viewController_ = [[CHViewController alloc] initWithPresenter:mockPresenter_]; 25 | mockViewController_ = OCMPartialMock(viewController_); 26 | } 27 | 28 | - (void)tearDown { 29 | OCMVerifyAll(mockPresenter_); 30 | OCMVerifyAll(mockNavigationController_); 31 | OCMVerifyAll(mockViewController_); 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testInit { 36 | OCMVerify([mockPresenter_ setViewController:viewController_]); 37 | } 38 | 39 | - (void)testViewDidLoad { 40 | OCMExpect([mockPresenter_ leftNavigationButtons]); 41 | OCMExpect([mockPresenter_ rightNavigationButtons]); 42 | OCMExpect([mockPresenter_ viewLoaded]); 43 | 44 | [viewController_ viewDidLoad]; 45 | } 46 | 47 | - (void)testViewWillDisappear { 48 | OCMExpect([mockPresenter_ viewWillDisappear]); 49 | [viewController_ viewWillDisappear:YES]; 50 | } 51 | 52 | - (void)testDismissViewController { 53 | [[[mockViewController_ expect] andReturn:mockNavigationController_] navigationController]; 54 | 55 | OCMExpect([mockNavigationController_ dismissViewControllerAnimated:NO completion:nil]); 56 | [viewController_ dismissViewControllerAnimated:NO withCompletionBlock:nil]; 57 | } 58 | 59 | - (void)testDismissViewControllerAnimated { 60 | [[[mockViewController_ expect] andReturn:mockNavigationController_] navigationController]; 61 | 62 | OCMExpect([mockNavigationController_ dismissViewControllerAnimated:YES completion:nil]); 63 | [viewController_ dismissViewControllerAnimated:YES withCompletionBlock:nil]; 64 | } 65 | 66 | - (void)testPushViewController { 67 | [[[mockViewController_ expect] andReturn:mockNavigationController_] navigationController]; 68 | 69 | OCMExpect([mockNavigationController_ pushViewController:[OCMArg any] animated:NO]); 70 | [viewController_ pushViewController:[UIViewController new] animated:NO]; 71 | } 72 | 73 | - (void)testPushViewControllerAnimated { 74 | [[[mockViewController_ expect] andReturn:mockNavigationController_] navigationController]; 75 | 76 | OCMExpect([mockNavigationController_ pushViewController:[OCMArg any] animated:YES]); 77 | [viewController_ pushViewController:[UIViewController new] animated:YES]; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/model/ComputerPlayerTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import "ComputerPlayer.h" 5 | #import "TicTacToeBoard.h" 6 | 7 | @interface ComputerPlayerTest : XCTestCase { 8 | TicTacToeBoard *board_; 9 | ComputerPlayer *player_; 10 | } 11 | 12 | // Counts how many squares are filled with that type. 13 | - (NSInteger)countFilledSquares:(TicTacToeStateType)type; 14 | @end 15 | 16 | @implementation ComputerPlayerTest 17 | 18 | - (NSInteger)countFilledSquares:(TicTacToeStateType)type { 19 | int count = 0; 20 | for (int x = 0; x < 3; x++) { 21 | for (int y = 0; y < 3; y++) { 22 | if ([board_ stateForXPos:x yPos:y] == type) { 23 | count++; 24 | } 25 | } 26 | } 27 | return count; 28 | } 29 | 30 | - (void)setUp { 31 | [super setUp]; 32 | 33 | board_ = [TicTacToeBoard new]; 34 | player_ = [[ComputerPlayer alloc] initWithBoard:board_ type:TicTacToeStateO]; 35 | } 36 | 37 | - (void)testNextMove { 38 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 0); 39 | [player_ makeNextMove]; 40 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 1); 41 | [player_ makeNextMove]; 42 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 2); 43 | [player_ makeNextMove]; 44 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 3); 45 | [player_ makeNextMove]; 46 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 4); 47 | [player_ makeNextMove]; 48 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 5); 49 | [player_ makeNextMove]; 50 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 6); 51 | [player_ makeNextMove]; 52 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 7); 53 | [player_ makeNextMove]; 54 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 8); 55 | [player_ makeNextMove]; 56 | XCTAssertEqual([self countFilledSquares:TicTacToeStateO], 9); 57 | } 58 | 59 | - (void)testCompleteRowOO_ { 60 | // TODO: Fill this in. 61 | } 62 | 63 | - (void)testCompleteRowO_O { 64 | // TODO: Fill this in. 65 | } 66 | 67 | - (void)testCompleteRow_OO { 68 | // TODO: Fill this in. 69 | } 70 | 71 | - (void)testCompleteColumnOO_ { 72 | // TODO: Fill this in. 73 | } 74 | 75 | - (void)testCompleteColumnO_O { 76 | [board_ playXPos:1 yPos:0 toState:TicTacToeStateO]; 77 | [board_ playXPos:1 yPos:2 toState:TicTacToeStateO]; 78 | 79 | [player_ makeNextMove]; 80 | 81 | XCTAssertEqual([board_ stateForXPos:1 yPos:1], TicTacToeStateO); 82 | } 83 | 84 | - (void)testCompleteColumn_OO { 85 | // TODO: Fill this in. 86 | } 87 | 88 | - (void)testBlockCompleteRowXX_ { 89 | // TODO: Fill this in. 90 | } 91 | 92 | - (void)testBlockCompleteRowX_X { 93 | // TODO: Fill this in. 94 | } 95 | 96 | - (void)testBlockCompleteRow_XX { 97 | // TODO: Fill this in. 98 | } 99 | 100 | - (void)testBlockCompleteColumnXX_ { 101 | // TODO: Fill this in. 102 | } 103 | 104 | - (void)testBlockCompleteColumnX_X { 105 | // TODO: Fill this in. 106 | } 107 | 108 | - (void)testBlockCompleteColumn_XX { 109 | // TODO: Fill this in. 110 | } 111 | 112 | - (void)testCompleteDiagonal1OO_ { 113 | // TODO: Fill this in. 114 | } 115 | 116 | - (void)testCompleteDiagonal1O_O { 117 | // TODO: Fill this in. 118 | } 119 | 120 | - (void)testCompleteDiagonal1_OO { 121 | // TODO: Fill this in. 122 | } 123 | 124 | - (void)testCompleteDiagonal2OO_ { 125 | // TODO: Fill this in. 126 | } 127 | 128 | - (void)testCompleteDiagonal2O_O { 129 | // TODO: Fill this in. 130 | } 131 | 132 | - (void)testCompleteDiagonal2_OO { 133 | // TODO: Fill this in. 134 | } 135 | 136 | - (void)testBlockDiagonal1OO_ { 137 | // TODO: Fill this in. 138 | } 139 | 140 | - (void)testBlockDiagonal1O_O { 141 | // TODO: Fill this in. 142 | } 143 | 144 | - (void)testBlockDiagonal1_OO { 145 | // TODO: Fill this in. 146 | } 147 | 148 | - (void)testBlockDiagonal2OO_ { 149 | // TODO: Fill this in. 150 | } 151 | 152 | - (void)testBlockDiagonal2O_O { 153 | // TODO: Fill this in. 154 | } 155 | 156 | - (void)testBlockDiagonal2_OO { 157 | // TODO: Fill this in. 158 | } 159 | 160 | - (void)testMultipleOptions { 161 | /** 162 | O | X | O 163 | _ | _ | _ 164 | X | X | O 165 | */ 166 | [board_ playXPos:0 yPos:0 toState:TicTacToeStateO]; 167 | [board_ playXPos:1 yPos:0 toState:TicTacToeStateX]; 168 | [board_ playXPos:2 yPos:0 toState:TicTacToeStateO]; 169 | [board_ playXPos:0 yPos:2 toState:TicTacToeStateX]; 170 | [board_ playXPos:1 yPos:2 toState:TicTacToeStateX]; 171 | [board_ playXPos:2 yPos:2 toState:TicTacToeStateO]; 172 | 173 | [player_ makeNextMove]; 174 | 175 | // TODO: Fill this in. How can you tell if the test has passed? 176 | } 177 | 178 | - (void)testWinOrLose { 179 | /** 180 | X | X | O 181 | O | _ | _ 182 | X | X | O 183 | */ 184 | [board_ playXPos:0 yPos:0 toState:TicTacToeStateX]; 185 | [board_ playXPos:1 yPos:0 toState:TicTacToeStateX]; 186 | [board_ playXPos:2 yPos:0 toState:TicTacToeStateO]; 187 | [board_ playXPos:0 yPos:1 toState:TicTacToeStateO]; 188 | [board_ playXPos:0 yPos:2 toState:TicTacToeStateX]; 189 | [board_ playXPos:1 yPos:2 toState:TicTacToeStateX]; 190 | [board_ playXPos:2 yPos:2 toState:TicTacToeStateO]; 191 | 192 | [player_ makeNextMove]; 193 | 194 | // TODO: Fill this in. How can you tell if the test has passed? 195 | } 196 | 197 | @end 198 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/model/TicTacToeBoardTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import "TicTacToeBoard.h" 5 | 6 | @interface TicTacToeBoardTest : XCTestCase { 7 | TicTacToeBoard *board_; 8 | } 9 | 10 | @end 11 | 12 | @implementation TicTacToeBoardTest 13 | 14 | - (void)setUp { 15 | [super setUp]; 16 | board_ = [TicTacToeBoard new]; 17 | } 18 | 19 | - (void)testBoardInitializationAllEmpty { 20 | for (int x = 0; x < 3; x++) { 21 | for (int y = 0; y < 3; y++) { 22 | XCTAssertEqual([board_ stateForXPos:x yPos:y], TicTacToeStateEmpty); 23 | } 24 | } 25 | } 26 | 27 | - (void)testPlayValid { 28 | for (int x = 0; x < 3; x++) { 29 | for (int y = 0; y < 3; y++) { 30 | XCTAssertTrue([board_ playXPos:x yPos:y toState:TicTacToeStateO]); 31 | XCTAssertEqual([board_ stateForXPos:x yPos:y], TicTacToeStateO); 32 | } 33 | } 34 | } 35 | 36 | - (void)testStateNegativeX { 37 | XCTAssertEqual([board_ stateForXPos:-2 yPos:2], TicTacToeStateInvalid); 38 | } 39 | 40 | - (void)testStateXTooLarge { 41 | // TODO: Fill this in. 42 | } 43 | 44 | - (void)testStateNegativeY { 45 | // TODO: Fill this in. 46 | } 47 | 48 | - (void)testStateYTooLarge { 49 | // TODO: Fill this in. 50 | } 51 | 52 | - (void)testPlayNegativeX { 53 | // TODO: Fill this in. 54 | } 55 | 56 | - (void)testPlayXTooLarge { 57 | // TODO: Fill this in. 58 | } 59 | 60 | - (void)testPlayNegativeY { 61 | // TODO: Fill this in. 62 | } 63 | 64 | - (void)testPlayYTooLarge { 65 | XCTAssertFalse([board_ playXPos:2 yPos:3 toState:TicTacToeStateO]); 66 | } 67 | 68 | - (void)testPlayEmptyState { 69 | // TODO: Fill this in. 70 | } 71 | 72 | - (void)testPlayInvalidState { 73 | XCTAssertFalse([board_ playXPos:2 yPos:2 toState:TicTacToeStateInvalid]); 74 | } 75 | 76 | - (void)testPlayOverOtherPlay { 77 | XCTAssertTrue([board_ playXPos:1 yPos:1 toState:TicTacToeStateX]); 78 | XCTAssertFalse([board_ playXPos:1 yPos:1 toState:TicTacToeStateO]); 79 | XCTAssertEqual([board_ stateForXPos:1 yPos:1], TicTacToeStateX); 80 | } 81 | 82 | - (void)testGameStateWithSpaces { 83 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 84 | XCTAssertTrue([board_ playXPos:0 yPos:0 toState:TicTacToeStateO]); 85 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 86 | 87 | // TODO: Fill this in. 88 | } 89 | 90 | - (void)testGameStateFull { 91 | XCTAssertTrue([board_ playXPos:0 yPos:0 toState:TicTacToeStateO]); 92 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 93 | 94 | // TODO: Fill this in. 95 | 96 | XCTAssertEqual([board_ gameState], TicTacToeGameStateBoardFull); 97 | } 98 | 99 | - (void)testGameStateFullOWins { 100 | /* 101 | O | X | O 102 | X | O | X 103 | O | O | X 104 | */ 105 | XCTAssertTrue([board_ playXPos:0 yPos:0 toState:TicTacToeStateO]); 106 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 107 | XCTAssertTrue([board_ playXPos:1 yPos:0 toState:TicTacToeStateX]); 108 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 109 | XCTAssertTrue([board_ playXPos:2 yPos:0 toState:TicTacToeStateO]); 110 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 111 | XCTAssertTrue([board_ playXPos:0 yPos:1 toState:TicTacToeStateX]); 112 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 113 | XCTAssertTrue([board_ playXPos:2 yPos:1 toState:TicTacToeStateX]); 114 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 115 | XCTAssertTrue([board_ playXPos:0 yPos:2 toState:TicTacToeStateO]); 116 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 117 | XCTAssertTrue([board_ playXPos:1 yPos:2 toState:TicTacToeStateO]); 118 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 119 | XCTAssertTrue([board_ playXPos:2 yPos:2 toState:TicTacToeStateX]); 120 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 121 | 122 | XCTAssertTrue([board_ playXPos:1 yPos:1 toState:TicTacToeStateO]); 123 | XCTAssertEqual([board_ gameState], TicTacToeGameStateOWin); 124 | } 125 | 126 | - (void)testGameStateFullXWins { 127 | /* 128 | X | O | X 129 | O | X | O 130 | X | X | O 131 | */ 132 | XCTAssertTrue([board_ playXPos:0 yPos:0 toState:TicTacToeStateX]); 133 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 134 | XCTAssertTrue([board_ playXPos:0 yPos:1 toState:TicTacToeStateO]); 135 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 136 | XCTAssertTrue([board_ playXPos:0 yPos:2 toState:TicTacToeStateX]); 137 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 138 | XCTAssertTrue([board_ playXPos:1 yPos:0 toState:TicTacToeStateO]); 139 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 140 | XCTAssertTrue([board_ playXPos:1 yPos:2 toState:TicTacToeStateX]); 141 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 142 | XCTAssertTrue([board_ playXPos:2 yPos:0 toState:TicTacToeStateX]); 143 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 144 | XCTAssertTrue([board_ playXPos:2 yPos:1 toState:TicTacToeStateO]); 145 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 146 | XCTAssertTrue([board_ playXPos:2 yPos:2 toState:TicTacToeStateO]); 147 | XCTAssertEqual([board_ gameState], TicTacToeGameStateNotEnded); 148 | 149 | XCTAssertTrue([board_ playXPos:1 yPos:1 toState:TicTacToeStateX]); 150 | XCTAssertEqual([board_ gameState], TicTacToeGameStateXWin); 151 | } 152 | 153 | - (void)testHorizontalOWin1 { 154 | // TODO: Fill this in. 155 | } 156 | 157 | - (void)testHorizontalXWin1 { 158 | // TODO: Fill this in. 159 | } 160 | 161 | 162 | - (void)testHorizontalOWin2 { 163 | // TODO: Fill this in. 164 | } 165 | 166 | - (void)testHorizontalXWin2 { 167 | // TODO: Fill this in. 168 | } 169 | 170 | - (void)testHorizontalOWin3 { 171 | // TODO: Fill this in. 172 | } 173 | 174 | - (void)testHorizontalXWin3 { 175 | // TODO: Fill this in. 176 | } 177 | 178 | - (void)testVerticalOWin1 { 179 | // TODO: Fill this in. 180 | } 181 | 182 | - (void)testVerticalXWin1 { 183 | // TODO: Fill this in. 184 | } 185 | 186 | - (void)testVerticalOWin2 { 187 | // TODO: Fill this in. 188 | } 189 | 190 | - (void)testVerticalXWin2 { 191 | // TODO: Fill this in. 192 | } 193 | 194 | - (void)testVerticalOWin3 { 195 | // TODO: Fill this in. 196 | } 197 | 198 | - (void)testVerticalXWin3 { 199 | // TODO: Fill this in. 200 | } 201 | 202 | - (void)testDiagonalOWin1 { 203 | // TODO: Fill this in. 204 | } 205 | 206 | - (void)testDiagonalXWin1 { 207 | // TODO: Fill this in. 208 | } 209 | 210 | - (void)testDiagonalOWin2 { 211 | // TODO: Fill this in. 212 | } 213 | 214 | - (void)testDiagonalXWin2 { 215 | // TODO: Fill this in. 216 | } 217 | 218 | @end 219 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/presenters/EndGamePresenterTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "EndGamePresenter.h" 6 | #import "EndGameView.h" 7 | #import "EndGameViewController.h" 8 | #import "HomeViewController.h" 9 | 10 | @interface EndGamePresenterTest : XCTestCase { 11 | id mockView_; 12 | id mockViewController_; 13 | id presenter_; 14 | } 15 | 16 | @end 17 | 18 | @implementation EndGamePresenterTest 19 | 20 | - (void)setUp { 21 | [super setUp]; 22 | 23 | mockViewController_ = OCMStrictClassMock([EndGameViewController class]); 24 | mockView_ = OCMStrictClassMock([EndGameView class]); 25 | OCMStub([mockViewController_ endGameView]).andReturn(mockView_); 26 | 27 | presenter_ = [[EndGamePresenter alloc] initWithEndGameState:TicTacToeGameStateBoardFull]; 28 | [presenter_ setViewController:mockViewController_]; 29 | } 30 | 31 | - (void)tearDown { 32 | OCMVerifyAll(mockView_); 33 | OCMVerifyAll(mockViewController_); 34 | 35 | [super tearDown]; 36 | } 37 | 38 | - (void)testCreateViewControllerTie { 39 | EndGameViewController *viewController = (EndGameViewController *) 40 | [EndGamePresenter createViewControllerWithEndGameState:TicTacToeGameStateBoardFull]; 41 | XCTAssertNotNil(viewController); 42 | 43 | EndGamePresenter *presenter = (EndGamePresenter *) [viewController presenter]; 44 | XCTAssertNotNil(presenter); 45 | 46 | [presenter viewLoaded]; 47 | 48 | XCTAssertEqualObjects([[[viewController endGameView] gameStateLabel] text], kTie); 49 | } 50 | 51 | - (void)testCreateViewControllerOWins { 52 | EndGameViewController *viewController = (EndGameViewController *) 53 | [EndGamePresenter createViewControllerWithEndGameState:TicTacToeGameStateOWin]; 54 | XCTAssertNotNil(viewController); 55 | 56 | EndGamePresenter *presenter = (EndGamePresenter *) [viewController presenter]; 57 | XCTAssertNotNil(presenter); 58 | 59 | [presenter viewLoaded]; 60 | 61 | XCTAssertEqualObjects([[[viewController endGameView] gameStateLabel] text], kOWin); 62 | } 63 | 64 | - (void)testCreateViewControllerXWins { 65 | EndGameViewController *viewController = (EndGameViewController *) 66 | [EndGamePresenter createViewControllerWithEndGameState:TicTacToeGameStateXWin]; 67 | XCTAssertNotNil(viewController); 68 | 69 | EndGamePresenter *presenter = (EndGamePresenter *) [viewController presenter]; 70 | XCTAssertNotNil(presenter); 71 | 72 | [presenter viewLoaded]; 73 | 74 | XCTAssertEqualObjects([[[viewController endGameView] gameStateLabel] text], kXWin); 75 | } 76 | 77 | - (void)testViewLoaded { 78 | id mockButton = OCMStrictClassMock([UIButton class]); 79 | OCMStub([mockView_ playAgainButton]).andReturn(mockButton); 80 | 81 | OCMExpect([mockViewController_ setGameOverStateText:[OCMArg any]]); 82 | OCMExpect([mockButton addTarget:presenter_ 83 | action:[OCMArg anySelector] 84 | forControlEvents:UIControlEventTouchUpInside]); 85 | 86 | [presenter_ viewLoaded]; 87 | } 88 | 89 | - (void)testTapPlayAgainButton { 90 | // Should launch a new navigation controller. 91 | UIButton *playAgainButton = [UIButton new]; 92 | OCMStub([mockView_ playAgainButton]).andReturn(playAgainButton); 93 | 94 | OCMExpect([mockViewController_ setGameOverStateText:[OCMArg any]]); 95 | [presenter_ viewLoaded]; 96 | 97 | BOOL (^verifyNavController)(id) = ^BOOL(id obj) { 98 | UINavigationController *navController = (UINavigationController *)obj; 99 | UIViewController *rootViewController = [[navController viewControllers] firstObject]; 100 | return [rootViewController isKindOfClass:[HomeViewController class]]; 101 | }; 102 | OCMExpect([mockViewController_ presentViewController:[OCMArg checkWithBlock:verifyNavController] 103 | animated:YES 104 | completion:nil]); 105 | 106 | [playAgainButton sendActionsForControlEvents:UIControlEventTouchUpInside]; 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/presenters/GamePresenterTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "ComputerPlayer.h" 6 | #import "GamePresenter.h" 7 | #import "GameView.h" 8 | #import "GameViewController.h" 9 | #import "TicTacToeBoard.h" 10 | #import "TicTacToeButton.h" 11 | 12 | @interface GamePresenterTest : XCTestCase { 13 | id mockBoard_; 14 | id mockComputerPlayer_; 15 | id mockView_; 16 | id mockViewController_; 17 | GamePresenter *presenter_; 18 | } 19 | // Sets expectations that the view will return these buttons, and a target will be added to each. 20 | - (void)setUpExpectationsForButtons:(NSArray *)buttons; 21 | @end 22 | 23 | @implementation GamePresenterTest 24 | 25 | - (void)setUp { 26 | [super setUp]; 27 | 28 | mockBoard_ = OCMStrictClassMock([TicTacToeBoard class]); 29 | mockComputerPlayer_ = OCMStrictClassMock([ComputerPlayer class]); 30 | mockView_ = OCMStrictClassMock([GameView class]); 31 | mockViewController_ = OCMStrictClassMock([GameViewController class]); 32 | OCMStub([mockViewController_ gameView]).andReturn(mockView_); 33 | 34 | presenter_ = [[GamePresenter alloc] initWithBoard:mockBoard_ 35 | computerPlayer:mockComputerPlayer_ 36 | gameType:TicTacToeGameUserO]; 37 | [presenter_ setViewController:mockViewController_]; 38 | } 39 | 40 | - (void)tearDown { 41 | OCMVerifyAll(mockBoard_); 42 | OCMVerifyAll(mockComputerPlayer_); 43 | OCMVerifyAll(mockView_); 44 | OCMVerifyAll(mockViewController_); 45 | 46 | [super tearDown]; 47 | } 48 | 49 | - (void)setUpExpectationsForButtons:(NSArray *)buttons { 50 | OCMStub([mockView_ buttons]).andReturn(buttons); 51 | 52 | for (id mockButton in buttons) { 53 | OCMExpect([mockButton addTarget:presenter_ 54 | action:[OCMArg anySelector] 55 | forControlEvents:UIControlEventTouchUpInside]); 56 | } 57 | } 58 | 59 | - (void)testViewLoadedComputerNotPlaying { 60 | presenter_ = [[GamePresenter alloc] initWithBoard:mockBoard_ 61 | computerPlayer:mockComputerPlayer_ 62 | gameType:TicTacToeGameUserXO]; 63 | [presenter_ setViewController:mockViewController_]; 64 | 65 | id mockButton1 = OCMStrictClassMock([UIButton class]); 66 | id mockButton2 = OCMStrictClassMock([UIButton class]); 67 | id mockButton3 = OCMStrictClassMock([UIButton class]); 68 | NSArray *buttons = @[mockButton1, mockButton2, mockButton3]; 69 | [self setUpExpectationsForButtons:buttons]; 70 | 71 | [presenter_ viewLoaded]; 72 | 73 | OCMVerifyAll(mockButton1); 74 | OCMVerifyAll(mockButton2); 75 | OCMVerifyAll(mockButton3); 76 | } 77 | 78 | - (void)testViewLoadedComputerNotFirst { 79 | // TODO: Fill this in. 80 | } 81 | 82 | - (void)testViewLoadedComputerGoesFirst { 83 | // Create the expectation. 84 | XCTestExpectation *expectation = 85 | [self expectationWithDescription:@"testViewLoadedComputerGoesFirst"]; 86 | 87 | // Create the presenter to test. 88 | presenter_ = [[GamePresenter alloc] initWithBoard:mockBoard_ 89 | computerPlayer:mockComputerPlayer_ 90 | gameType:TicTacToeGameUserX]; 91 | [presenter_ setViewController:mockViewController_]; 92 | 93 | // Mock and stub some buttons. 94 | id mockButton1 = OCMStrictClassMock([UIButton class]); 95 | id mockButton2 = OCMStrictClassMock([UIButton class]); 96 | id mockButton3 = OCMStrictClassMock([UIButton class]); 97 | NSArray *buttons = @[mockButton1, mockButton2, mockButton3]; 98 | [self setUpExpectationsForButtons:buttons]; 99 | 100 | // Computer should play. 101 | OCMStub([mockBoard_ gameState]).andReturn(TicTacToeGameStateNotEnded); 102 | OCMExpect([mockComputerPlayer_ makeNextMove]); 103 | // Last thing that should happen after the computer plays, so fulfill expectation. 104 | OCMExpect([mockViewController_ updateDisplayFromBoard:mockBoard_]) 105 | .andDo(^(NSInvocation *invocation){ 106 | [expectation fulfill]; 107 | }); 108 | 109 | [presenter_ viewLoaded]; 110 | 111 | // Wait for expecations. 112 | [self waitForExpectationsWithTimeout:2 handler:nil]; 113 | 114 | // Verify the buttons. 115 | OCMVerifyAll(mockButton1); 116 | OCMVerifyAll(mockButton2); 117 | OCMVerifyAll(mockButton3); 118 | } 119 | 120 | - (void)testButtonPressedComputerPlaying { 121 | TicTacToeButton *button = [[TicTacToeButton alloc] initWithX:1 y:2]; 122 | NSArray *buttons = @[button]; 123 | 124 | OCMExpect([mockView_ buttons]).andReturn(buttons); 125 | 126 | [presenter_ viewLoaded]; 127 | 128 | [presenter_ setComputerInPlay:YES]; 129 | [button sendActionsForControlEvents:UIControlEventTouchUpInside]; 130 | } 131 | 132 | - (void)testButtonPressedSquareSetAlready { 133 | // TODO: Fill this in. 134 | } 135 | 136 | - (void)testButtonPressedThenGameOver { 137 | // TODO: Fill this in. 138 | } 139 | 140 | - (void)testButtonPressedUserThenUser { 141 | presenter_ = [[GamePresenter alloc] initWithBoard:mockBoard_ 142 | computerPlayer:mockComputerPlayer_ 143 | gameType:TicTacToeGameUserXO]; 144 | [presenter_ setViewController:mockViewController_]; 145 | 146 | TicTacToeButton *button1 = [[TicTacToeButton alloc] initWithX:1 y:2]; 147 | TicTacToeButton *button2 = [[TicTacToeButton alloc] initWithX:2 y:0]; 148 | NSArray *buttons = @[button1, button2]; 149 | 150 | OCMExpect([mockView_ buttons]).andReturn(buttons); 151 | 152 | [presenter_ viewLoaded]; 153 | 154 | OCMExpect([mockBoard_ playXPos:1 yPos:2 toState:TicTacToeStateO]).andReturn(YES); 155 | OCMExpect([mockViewController_ updateDisplayFromBoard:mockBoard_]); 156 | OCMExpect([mockBoard_ gameState]).andReturn(TicTacToeGameStateNotEnded); 157 | 158 | [button1 sendActionsForControlEvents:UIControlEventTouchUpInside]; 159 | 160 | OCMExpect([mockBoard_ playXPos:2 yPos:0 toState:TicTacToeStateX]).andReturn(YES); 161 | OCMExpect([mockViewController_ updateDisplayFromBoard:mockBoard_]); 162 | OCMExpect([mockBoard_ gameState]).andReturn(TicTacToeGameStateNotEnded); 163 | 164 | [button2 sendActionsForControlEvents:UIControlEventTouchUpInside]; 165 | } 166 | 167 | - (void)testButtonPressedUserThenComputer { 168 | // TODO: Fill this in. 169 | } 170 | 171 | @end 172 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/presenters/HomePresenterTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "GamePresenter.h" 6 | #import "GameViewController.h" 7 | #import "HomePresenter.h" 8 | #import "HomeView.h" 9 | #import "HomeViewController.h" 10 | 11 | @interface HomePresenterTest : XCTestCase { 12 | id mockView_; 13 | id mockViewController_; 14 | HomePresenter *presenter_; 15 | } 16 | 17 | @end 18 | 19 | @implementation HomePresenterTest 20 | 21 | - (void)setUp { 22 | [super setUp]; 23 | 24 | mockView_ = OCMStrictClassMock([HomeView class]); 25 | mockViewController_ = OCMStrictClassMock([HomeViewController class]); 26 | OCMStub([mockViewController_ homeView]).andReturn(mockView_); 27 | 28 | presenter_ = [HomePresenter new]; 29 | [presenter_ setViewController:mockViewController_]; 30 | } 31 | 32 | - (void)tearDown { 33 | OCMVerifyAll(mockView_); 34 | OCMVerifyAll(mockViewController_); 35 | 36 | [super tearDown]; 37 | } 38 | 39 | - (void)testCreateViewController { 40 | HomeViewController *viewController = (HomeViewController *) [HomePresenter createViewController]; 41 | XCTAssertNotNil(viewController); 42 | 43 | HomePresenter *presenter = (HomePresenter *) [viewController presenter]; 44 | XCTAssertNotNil(presenter); 45 | } 46 | 47 | - (void)testAddTargetsToButtons { 48 | // Create mocks for buttons. 49 | id mockOButton = OCMStrictClassMock([UIButton class]); 50 | id mockXButton = OCMStrictClassMock([UIButton class]); 51 | id mockXOButton = OCMStrictClassMock([UIButton class]); 52 | 53 | // Stub the view to return our mock buttons. 54 | OCMStub([mockView_ playOButton]).andReturn(mockOButton); 55 | OCMStub([mockView_ playXButton]).andReturn(mockXButton); 56 | OCMStub([mockView_ playXOButton]).andReturn(mockXOButton); 57 | 58 | // Expect targets to be set on them. 59 | OCMExpect([mockOButton addTarget:presenter_ 60 | action:[OCMArg anySelector] 61 | forControlEvents:UIControlEventTouchUpInside]); 62 | OCMExpect([mockXButton addTarget:presenter_ 63 | action:[OCMArg anySelector] 64 | forControlEvents:UIControlEventTouchUpInside]); 65 | OCMExpect([mockXOButton addTarget:presenter_ 66 | action:[OCMArg anySelector] 67 | forControlEvents:UIControlEventTouchUpInside]); 68 | 69 | // Call the method under test. 70 | [presenter_ viewLoaded]; 71 | 72 | // Verify the buttons. 73 | OCMVerifyAll(mockOButton); 74 | OCMVerifyAll(mockXButton); 75 | OCMVerifyAll(mockXOButton); 76 | } 77 | 78 | - (void)testOButtonPressed { 79 | UIButton *oButton = [UIButton new]; 80 | id mockXButton = OCMClassMock([UIButton class]); 81 | id mockXOButton = OCMClassMock([UIButton class]); 82 | 83 | OCMStub([mockView_ playOButton]).andReturn(oButton); 84 | OCMStub([mockView_ playXButton]).andReturn(mockXButton); 85 | OCMStub([mockView_ playXOButton]).andReturn(mockXOButton); 86 | 87 | BOOL (^verifyGameType)(id) = ^BOOL(id obj) { 88 | // Cast to a GameViewController. 89 | GameViewController *gameViewController = (GameViewController *) obj; 90 | // Access the presenter. 91 | GamePresenter *presenter = (GamePresenter *) [gameViewController presenter]; 92 | // Make sure gameType is correct. 93 | return [presenter gameType] == TicTacToeGameUserO; 94 | }; 95 | OCMExpect([mockViewController_ pushViewController:[OCMArg checkWithBlock:verifyGameType] 96 | animated:YES]); 97 | 98 | [presenter_ viewLoaded]; 99 | 100 | [oButton sendActionsForControlEvents:UIControlEventTouchUpInside]; 101 | 102 | OCMVerifyAll(mockXButton); 103 | OCMVerifyAll(mockXOButton); 104 | } 105 | 106 | - (void)testXButtonPressed { 107 | // TODO: Fill this in. 108 | } 109 | 110 | - (void)testXOButtonPressed { 111 | // TODO: Fill this in. 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/viewcontrollers/EndGameViewControllerTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "EndGamePresenter.h" 6 | #import "EndGameView.h" 7 | #import "EndGameViewController.h" 8 | 9 | @interface EndGameViewControllerTest : XCTestCase { 10 | id mockPresenter_; 11 | EndGameViewController *viewController_; 12 | } 13 | @end 14 | 15 | @implementation EndGameViewControllerTest 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | mockPresenter_ = OCMStrictClassMock([EndGamePresenter class]); 21 | OCMExpect([mockPresenter_ setViewController:[OCMArg any]]); 22 | viewController_ = [[EndGameViewController alloc] initWithPresenter:mockPresenter_]; 23 | } 24 | 25 | - (void)tearDown { 26 | OCMVerifyAll(mockPresenter_); 27 | 28 | [super tearDown]; 29 | } 30 | 31 | - (void)testViewLoaded { 32 | OCMExpect([mockPresenter_ leftNavigationButtons]); 33 | OCMExpect([mockPresenter_ rightNavigationButtons]); 34 | OCMExpect([mockPresenter_ viewLoaded]); 35 | 36 | XCTAssertNotNil([viewController_ endGameView]); 37 | } 38 | 39 | - (void)testSetGameStateText { 40 | OCMExpect([mockPresenter_ leftNavigationButtons]).andReturn([NSArray array]); 41 | OCMExpect([mockPresenter_ rightNavigationButtons]).andReturn([NSArray array]); 42 | OCMExpect([mockPresenter_ viewLoaded]); 43 | 44 | NSString *gameState = @"anything goes"; 45 | [viewController_ setGameOverStateText:gameState]; 46 | XCTAssertEqualObjects([[[viewController_ endGameView] gameStateLabel] text], gameState); 47 | } 48 | 49 | @end 50 | 51 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/viewcontrollers/GameViewControllerTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "GamePresenter.h" 6 | #import "GameView.h" 7 | #import "GameViewController.h" 8 | #import "TicTacToeBoard.h" 9 | #import "TicTacToeButton.h" 10 | 11 | @interface GameViewControllerTest : XCTestCase { 12 | id mockPresenter_; 13 | GameViewController *viewController_; 14 | } 15 | - (void)setExpectationsForLoadingView; 16 | @end 17 | 18 | @implementation GameViewControllerTest 19 | 20 | - (void)setUp { 21 | [super setUp]; 22 | 23 | mockPresenter_ = OCMStrictClassMock([GamePresenter class]); 24 | OCMExpect([mockPresenter_ setViewController:[OCMArg any]]); 25 | viewController_ = [[GameViewController alloc] initWithPresenter:mockPresenter_]; 26 | } 27 | 28 | - (void)tearDown { 29 | OCMVerifyAll(mockPresenter_); 30 | 31 | [super tearDown]; 32 | } 33 | 34 | - (void)setExpectationsForLoadingView { 35 | OCMExpect([mockPresenter_ leftNavigationButtons]); 36 | OCMExpect([mockPresenter_ rightNavigationButtons]); 37 | OCMExpect([mockPresenter_ viewLoaded]); 38 | } 39 | 40 | - (void)testView { 41 | [self setExpectationsForLoadingView]; 42 | XCTAssertNotNil([viewController_ gameView]); 43 | } 44 | 45 | - (void)testValueForStateO { 46 | XCTAssertEqualObjects([viewController_ valueForState:TicTacToeStateO], kO); 47 | } 48 | 49 | - (void)testValueForStateX { 50 | XCTAssertEqualObjects([viewController_ valueForState:TicTacToeStateX], kX); 51 | } 52 | 53 | - (void)testValueForStateEmpty { 54 | XCTAssertEqualObjects([viewController_ valueForState:TicTacToeStateEmpty], kEmpty); 55 | } 56 | 57 | - (void)testValueForStateInvalid { 58 | XCTAssertEqualObjects([viewController_ valueForState:TicTacToeStateInvalid], kEmpty); 59 | } 60 | 61 | - (void)testUpdateBoardSymmetrical { 62 | [self setExpectationsForLoadingView]; 63 | 64 | TicTacToeBoard *board = [[TicTacToeBoard alloc] init]; 65 | [board playXPos:0 yPos:0 toState:TicTacToeStateO]; 66 | [board playXPos:1 yPos:0 toState:TicTacToeStateX]; 67 | [board playXPos:2 yPos:0 toState:TicTacToeStateO]; 68 | [board playXPos:0 yPos:1 toState:TicTacToeStateX]; 69 | [board playXPos:1 yPos:1 toState:TicTacToeStateO]; 70 | [board playXPos:2 yPos:1 toState:TicTacToeStateX]; 71 | [board playXPos:0 yPos:2 toState:TicTacToeStateO]; 72 | [board playXPos:1 yPos:2 toState:TicTacToeStateX]; 73 | [board playXPos:2 yPos:2 toState:TicTacToeStateO]; 74 | 75 | [viewController_ updateDisplayFromBoard:board]; 76 | GameView *gameView = [viewController_ gameView]; 77 | 78 | XCTAssertEqualObjects([[gameView buttonAtX:0 y:0] titleForState:UIControlStateNormal], kO); 79 | XCTAssertEqualObjects([[gameView buttonAtX:1 y:0] titleForState:UIControlStateNormal], kX); 80 | XCTAssertEqualObjects([[gameView buttonAtX:2 y:0] titleForState:UIControlStateNormal], kO); 81 | XCTAssertEqualObjects([[gameView buttonAtX:0 y:1] titleForState:UIControlStateNormal], kX); 82 | XCTAssertEqualObjects([[gameView buttonAtX:1 y:1] titleForState:UIControlStateNormal], kO); 83 | XCTAssertEqualObjects([[gameView buttonAtX:2 y:1] titleForState:UIControlStateNormal], kX); 84 | XCTAssertEqualObjects([[gameView buttonAtX:0 y:2] titleForState:UIControlStateNormal], kO); 85 | XCTAssertEqualObjects([[gameView buttonAtX:1 y:2] titleForState:UIControlStateNormal], kX); 86 | XCTAssertEqualObjects([[gameView buttonAtX:2 y:2] titleForState:UIControlStateNormal], kO); 87 | } 88 | 89 | - (void)testUpdateBoardNotSymmetrical { 90 | [self setExpectationsForLoadingView]; 91 | 92 | TicTacToeBoard *board = [[TicTacToeBoard alloc] init]; 93 | [board playXPos:0 yPos:0 toState:TicTacToeStateO]; 94 | [board playXPos:1 yPos:0 toState:TicTacToeStateO]; 95 | [board playXPos:2 yPos:0 toState:TicTacToeStateO]; 96 | [board playXPos:0 yPos:1 toState:TicTacToeStateX]; 97 | [board playXPos:1 yPos:1 toState:TicTacToeStateO]; 98 | [board playXPos:2 yPos:1 toState:TicTacToeStateO]; 99 | [board playXPos:0 yPos:2 toState:TicTacToeStateX]; 100 | [board playXPos:1 yPos:2 toState:TicTacToeStateX]; 101 | [board playXPos:2 yPos:2 toState:TicTacToeStateX]; 102 | 103 | [viewController_ updateDisplayFromBoard:board]; 104 | GameView *gameView = [viewController_ gameView]; 105 | 106 | XCTAssertEqualObjects([[gameView buttonAtX:0 y:0] titleForState:UIControlStateNormal], kO); 107 | XCTAssertEqualObjects([[gameView buttonAtX:1 y:0] titleForState:UIControlStateNormal], kO); 108 | XCTAssertEqualObjects([[gameView buttonAtX:2 y:0] titleForState:UIControlStateNormal], kO); 109 | XCTAssertEqualObjects([[gameView buttonAtX:0 y:1] titleForState:UIControlStateNormal], kX); 110 | XCTAssertEqualObjects([[gameView buttonAtX:1 y:1] titleForState:UIControlStateNormal], kO); 111 | XCTAssertEqualObjects([[gameView buttonAtX:2 y:1] titleForState:UIControlStateNormal], kO); 112 | XCTAssertEqualObjects([[gameView buttonAtX:0 y:2] titleForState:UIControlStateNormal], kX); 113 | XCTAssertEqualObjects([[gameView buttonAtX:1 y:2] titleForState:UIControlStateNormal], kX); 114 | XCTAssertEqualObjects([[gameView buttonAtX:2 y:2] titleForState:UIControlStateNormal], kX); 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/viewcontrollers/HomeViewControllerTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "HomePresenter.h" 6 | #import "HomeViewController.h" 7 | 8 | @interface HomeViewControllerTest : XCTestCase { 9 | id mockPresenter_; 10 | HomeViewController *viewController_; 11 | } 12 | @end 13 | 14 | @implementation HomeViewControllerTest 15 | 16 | - (void)setUp { 17 | [super setUp]; 18 | 19 | mockPresenter_ = OCMStrictClassMock([HomePresenter class]); 20 | OCMExpect([mockPresenter_ setViewController:[OCMArg any]]); 21 | viewController_ = [[HomeViewController alloc] initWithPresenter:mockPresenter_]; 22 | OCMVerify([mockPresenter_ setViewController:viewController_]); 23 | } 24 | 25 | - (void)tearDown { 26 | OCMVerifyAll(mockPresenter_); 27 | 28 | [super tearDown]; 29 | } 30 | 31 | - (void)testViewLoaded { 32 | // TODO: Fill this in. 33 | 34 | XCTAssertNotNil([viewController_ homeView]); 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /TicTacToe/TicTacToeTests/views/GameViewTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import "GameView.h" 5 | #import "TicTacToeButton.h" 6 | 7 | @interface GameViewTest : XCTestCase { 8 | GameView *gameView_; 9 | } 10 | 11 | @end 12 | 13 | @implementation GameViewTest 14 | 15 | - (void)setUp { 16 | gameView_ = [GameView new]; 17 | } 18 | 19 | - (void)testButtons { 20 | // There should be 9 buttons. They should all be distinct. 21 | NSArray *buttons = [gameView_ buttons]; 22 | XCTAssertEqual([buttons count], 9); 23 | 24 | for (int i = 0; i < [buttons count]; i++) { 25 | for (int j = i + 1; j < [buttons count]; j++) { 26 | XCTAssertNotEqual(buttons[i], buttons[j]); 27 | } 28 | } 29 | } 30 | 31 | - (void)testButtonXYs { 32 | // Should be one with each x,y value. 33 | NSArray *buttons = [gameView_ buttons]; 34 | for (int x = 0; x < 3; x++) { 35 | for (int y = 0; y < 3; y++) { 36 | BOOL found = NO; 37 | for (TicTacToeButton *button in buttons) { 38 | if ([button x] == x && [button y] == y) { 39 | found = YES; 40 | break; 41 | } 42 | } 43 | XCTAssertTrue(found); 44 | } 45 | } 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/NSNotificationCenter+OCMAdditions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | 19 | @class OCObserverMockObject; 20 | 21 | 22 | @interface NSNotificationCenter(OCMAdditions) 23 | 24 | - (void)addMockObserver:(OCObserverMockObject *)notificationObserver name:(NSString *)notificationName object:(id)notificationSender; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMArg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface OCMArg : NSObject 20 | 21 | // constraining arguments 22 | 23 | + (id)any; 24 | + (SEL)anySelector; 25 | + (void *)anyPointer; 26 | + (id __autoreleasing *)anyObjectRef; 27 | + (id)isNil; 28 | + (id)isNotNil; 29 | + (id)isEqual:(id)value; 30 | + (id)isNotEqual:(id)value; 31 | + (id)isKindOfClass:(Class)cls; 32 | + (id)checkWithSelector:(SEL)selector onObject:(id)anObject; 33 | + (id)checkWithBlock:(BOOL (^)(id obj))block; 34 | 35 | // manipulating arguments 36 | 37 | + (id *)setTo:(id)value; 38 | + (void *)setToValue:(NSValue *)value; 39 | 40 | // internal use only 41 | 42 | + (id)resolveSpecialValues:(NSValue *)value; 43 | 44 | @end 45 | 46 | #define OCMOCK_ANY [OCMArg any] 47 | 48 | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) 49 | #define OCMOCK_VALUE(variable) \ 50 | ({ __typeof__(variable) __v = (variable); [NSValue value:&__v withObjCType:@encode(__typeof__(__v))]; }) 51 | #else 52 | #define OCMOCK_VALUE(variable) [NSValue value:&variable withObjCType:@encode(__typeof__(variable))] 53 | #endif 54 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMConstraint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | 19 | 20 | @interface OCMConstraint : NSObject 21 | 22 | + (instancetype)constraint; 23 | - (BOOL)evaluate:(id)value; 24 | 25 | // if you are looking for any, isNil, etc, they have moved to OCMArg 26 | 27 | // try to use [OCMArg checkWith...] instead of the constraintWith... methods below 28 | 29 | + (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject; 30 | + (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject withValue:(id)aValue; 31 | 32 | 33 | @end 34 | 35 | @interface OCMAnyConstraint : OCMConstraint 36 | @end 37 | 38 | @interface OCMIsNilConstraint : OCMConstraint 39 | @end 40 | 41 | @interface OCMIsNotNilConstraint : OCMConstraint 42 | @end 43 | 44 | @interface OCMIsNotEqualConstraint : OCMConstraint 45 | { 46 | @public 47 | id testValue; 48 | } 49 | 50 | @end 51 | 52 | @interface OCMInvocationConstraint : OCMConstraint 53 | { 54 | @public 55 | NSInvocation *invocation; 56 | } 57 | 58 | @end 59 | 60 | @interface OCMBlockConstraint : OCMConstraint 61 | { 62 | BOOL (^block)(id); 63 | } 64 | 65 | - (instancetype)initWithConstraintBlock:(BOOL (^)(id))block; 66 | 67 | @end 68 | 69 | 70 | #define CONSTRAINT(aSelector) [OCMConstraint constraintWithSelector:aSelector onObject:self] 71 | #define CONSTRAINTV(aSelector, aValue) [OCMConstraint constraintWithSelector:aSelector onObject:self withValue:(aValue)] 72 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMLocation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface OCMLocation : NSObject 20 | { 21 | id testCase; 22 | NSString *file; 23 | NSUInteger line; 24 | } 25 | 26 | + (instancetype)locationWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine; 27 | 28 | - (instancetype)initWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine; 29 | 30 | - (id)testCase; 31 | - (NSString *)file; 32 | - (NSUInteger)line; 33 | 34 | @end 35 | 36 | extern OCMLocation *OCMMakeLocation(id testCase, const char *file, int line); 37 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMMacroState.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | 19 | @class OCMLocation; 20 | @class OCMRecorder; 21 | @class OCMStubRecorder; 22 | @class OCMockObject; 23 | 24 | 25 | @interface OCMMacroState : NSObject 26 | { 27 | OCMRecorder *recorder; 28 | } 29 | 30 | + (void)beginStubMacro; 31 | + (OCMStubRecorder *)endStubMacro; 32 | 33 | + (void)beginExpectMacro; 34 | + (OCMStubRecorder *)endExpectMacro; 35 | 36 | + (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation; 37 | + (void)endVerifyMacro; 38 | 39 | + (OCMMacroState *)globalState; 40 | 41 | - (OCMRecorder *)recorder; 42 | 43 | - (void)switchToClassMethod; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMRecorder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | 19 | @class OCMockObject; 20 | @class OCMInvocationMatcher; 21 | 22 | 23 | @interface OCMRecorder : NSProxy 24 | { 25 | OCMockObject *mockObject; 26 | OCMInvocationMatcher *invocationMatcher; 27 | } 28 | 29 | - (instancetype)init; 30 | - (instancetype)initWithMockObject:(OCMockObject *)aMockObject; 31 | 32 | - (void)setMockObject:(OCMockObject *)aMockObject; 33 | 34 | - (OCMInvocationMatcher *)invocationMatcher; 35 | 36 | - (id)classMethod; 37 | - (id)ignoringNonObjectArgs; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMStubRecorder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import "OCMRecorder.h" 18 | 19 | 20 | @interface OCMStubRecorder : OCMRecorder 21 | 22 | - (id)andReturn:(id)anObject; 23 | - (id)andReturnValue:(NSValue *)aValue; 24 | - (id)andThrow:(NSException *)anException; 25 | - (id)andPost:(NSNotification *)aNotification; 26 | - (id)andCall:(SEL)selector onObject:(id)anObject; 27 | - (id)andDo:(void (^)(NSInvocation *invocation))block; 28 | - (id)andForwardToRealObject; 29 | 30 | @end 31 | 32 | 33 | @interface OCMStubRecorder (Properties) 34 | 35 | #define andReturn(aValue) _andReturn(({ typeof(aValue) _v = (aValue); [NSValue value:&_v withObjCType:@encode(typeof(_v))]; })) 36 | @property (nonatomic, readonly) OCMStubRecorder *(^ _andReturn)(NSValue *); 37 | 38 | #define andThrow(anException) _andThrow(anException) 39 | @property (nonatomic, readonly) OCMStubRecorder *(^ _andThrow)(NSException *); 40 | 41 | #define andPost(aNotification) _andPost(aNotification) 42 | @property (nonatomic, readonly) OCMStubRecorder *(^ _andPost)(NSNotification *); 43 | 44 | #define andCall(anObject, aSelector) _andCall(anObject, aSelector) 45 | @property (nonatomic, readonly) OCMStubRecorder *(^ _andCall)(id, SEL); 46 | 47 | #define andDo(aBlock) _andDo(aBlock) 48 | @property (nonatomic, readonly) OCMStubRecorder *(^ _andDo)(void (^)(NSInvocation *)); 49 | 50 | #define andForwardToRealObject() _andForwardToRealObject() 51 | @property (nonatomic, readonly) OCMStubRecorder *(^ _andForwardToRealObject)(void); 52 | 53 | @end 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | 26 | 27 | #define OCMClassMock(cls) [OCMockObject niceMockForClass:cls] 28 | 29 | #define OCMStrictClassMock(cls) [OCMockObject mockForClass:cls] 30 | 31 | #define OCMProtocolMock(protocol) [OCMockObject niceMockForProtocol:protocol] 32 | 33 | #define OCMStrictProtocolMock(protocol) [OCMockObject mockForProtocol:protocol] 34 | 35 | #define OCMPartialMock(obj) [OCMockObject partialMockForObject:obj] 36 | 37 | #define OCMObserverMock() [OCMockObject observerMock] 38 | 39 | 40 | #define OCMStub(invocation) \ 41 | ({ \ 42 | _OCMSilenceWarnings( \ 43 | [OCMMacroState beginStubMacro]; \ 44 | invocation; \ 45 | [OCMMacroState endStubMacro]; \ 46 | ); \ 47 | }) 48 | 49 | #define OCMExpect(invocation) \ 50 | ({ \ 51 | _OCMSilenceWarnings( \ 52 | [OCMMacroState beginExpectMacro]; \ 53 | invocation; \ 54 | [OCMMacroState endExpectMacro]; \ 55 | ); \ 56 | }) 57 | 58 | #define ClassMethod(invocation) \ 59 | _OCMSilenceWarnings( \ 60 | [[OCMMacroState globalState] switchToClassMethod]; \ 61 | invocation; \ 62 | ); 63 | 64 | 65 | #define OCMVerifyAll(mock) [mock verifyAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)] 66 | 67 | #define OCMVerifyAllWithDelay(mock, delay) [mock verifyWithDelay:delay atLocation:OCMMakeLocation(self, __FILE__, __LINE__)] 68 | 69 | #define OCMVerify(invocation) \ 70 | ({ \ 71 | _OCMSilenceWarnings( \ 72 | [OCMMacroState beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]; \ 73 | invocation; \ 74 | [OCMMacroState endVerifyMacro]; \ 75 | ); \ 76 | }) 77 | 78 | #define _OCMSilenceWarnings(macro) \ 79 | ({ \ 80 | _Pragma("clang diagnostic push") \ 81 | _Pragma("clang diagnostic ignored \"-Wunused-value\"") \ 82 | macro \ 83 | _Pragma("clang diagnostic pop") \ 84 | }) 85 | -------------------------------------------------------------------------------- /TicTacToe/includes/OCMock/OCMockObject.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2014 Erik Doernenburg and contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | * not use these files except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | #import 18 | 19 | @class OCMLocation; 20 | @class OCMInvocationStub; 21 | @class OCMStubRecorder; 22 | @class OCMInvocationMatcher; 23 | @class OCMInvocationExpectation; 24 | 25 | 26 | @interface OCMockObject : NSProxy 27 | { 28 | BOOL isNice; 29 | BOOL expectationOrderMatters; 30 | NSMutableArray *stubs; 31 | NSMutableArray *expectations; 32 | NSMutableArray *exceptions; 33 | NSMutableArray *invocations; 34 | } 35 | 36 | + (id)mockForClass:(Class)aClass; 37 | + (id)mockForProtocol:(Protocol *)aProtocol; 38 | + (id)partialMockForObject:(NSObject *)anObject; 39 | 40 | + (id)niceMockForClass:(Class)aClass; 41 | + (id)niceMockForProtocol:(Protocol *)aProtocol; 42 | 43 | + (id)observerMock; 44 | 45 | - (instancetype)init; 46 | 47 | - (void)setExpectationOrderMatters:(BOOL)flag; 48 | 49 | - (id)stub; 50 | - (id)expect; 51 | - (id)reject; 52 | 53 | - (id)verify; 54 | - (id)verifyAtLocation:(OCMLocation *)location; 55 | 56 | - (void)verifyWithDelay:(NSTimeInterval)delay; 57 | - (void)verifyWithDelay:(NSTimeInterval)delay atLocation:(OCMLocation *)location; 58 | 59 | - (void)stopMocking; 60 | 61 | // internal use only 62 | 63 | - (void)addStub:(OCMInvocationStub *)aStub; 64 | - (void)addExpectation:(OCMInvocationExpectation *)anExpectation; 65 | 66 | - (BOOL)handleInvocation:(NSInvocation *)anInvocation; 67 | - (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation; 68 | - (BOOL)handleSelector:(SEL)sel; 69 | 70 | - (void)verifyInvocation:(OCMInvocationMatcher *)matcher; 71 | - (void)verifyInvocation:(OCMInvocationMatcher *)matcher atLocation:(OCMLocation *)location; 72 | 73 | @end 74 | 75 | -------------------------------------------------------------------------------- /TicTacToe/includes/libOCMock.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catehstn/ios-unit-testing/347e24435ecab47590f46271174122e885994b3a/TicTacToe/includes/libOCMock.a --------------------------------------------------------------------------------