diff --git a/CHANGELOG.md b/CHANGELOG.md index 75dc300..74535eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * [#41](https://github.com/Antondomashnev/FBSnapshotsViewer/pull/41): Add additional information for tests - [@antondomashnev](https://github.com/antondomashnev). * [#44](https://github.com/Antondomashnev/FBSnapshotsViewer/pull/44): Compact view redesign - [@antondomashnev](https://github.com/antondomashnev). * [#45](https://github.com/Antondomashnev/FBSnapshotsViewer/pull/45): Use Nuke for image loading - [@antondomashnev](https://github.com/antondomashnev). +* [47](https://github.com/Antondomashnev/FBSnapshotsViewer/pull/47): Swap snapshots - [@antondomashnev](https://github.com/antondomashnev). ### 0.5.0 (26.05.2017) diff --git a/FBSnapshotsViewer.xcodeproj/project.pbxproj b/FBSnapshotsViewer.xcodeproj/project.pbxproj index 3bc18d0..e4bd0b1 100644 --- a/FBSnapshotsViewer.xcodeproj/project.pbxproj +++ b/FBSnapshotsViewer.xcodeproj/project.pbxproj @@ -22,6 +22,12 @@ 6D130B6B1EC8E55F00E9642A /* PreferencesWireframeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D130B6A1EC8E55F00E9642A /* PreferencesWireframeSpec.swift */; }; 6D130B6D1EC8E82B00E9642A /* ConfigurationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D130B6C1EC8E82B00E9642A /* ConfigurationSpec.swift */; }; 6D130B6F1EC8EB2F00E9642A /* PreferencesDisplayInfoSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D130B6E1EC8EB2F00E9642A /* PreferencesDisplayInfoSpec.swift */; }; + 6D14776B1EFED5500070EFEC /* BuildCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D14776A1EFED5500070EFEC /* BuildCreator.swift */; }; + 6D14776D1EFED78D0070EFEC /* BuildCreatorSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D14776C1EFED78D0070EFEC /* BuildCreatorSpec.swift */; }; + 6D14776F1EFEDF5A0070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D14776E1EFEDF5A0070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift */; }; + 6D1477711EFEDFED0070EFEC /* FBReferenceImageDirectoryURLExtractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D1477701EFEDFED0070EFEC /* FBReferenceImageDirectoryURLExtractor.swift */; }; + 6D1477731EFEE7D00070EFEC /* FBReferenceImageDirectoryURLExtractorSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D1477721EFEE7D00070EFEC /* FBReferenceImageDirectoryURLExtractorSpec.swift */; }; + 6D1477751EFEEDB30070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D1477741EFEEDB30070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift */; }; 6D1C40761EFA628F00D4D5F1 /* Colors+AppleInterfaceMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D1C40751EFA628F00D4D5F1 /* Colors+AppleInterfaceMode.swift */; }; 6D21E66D1EAE9E3600800B91 /* ApplicationLogReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D21E66C1EAE9E3600800B91 /* ApplicationLogReader.swift */; }; 6D21E66F1EAEAA8A00800B91 /* ApplicationLogReaderSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D21E66E1EAEAA8A00800B91 /* ApplicationLogReaderSpec.swift */; }; @@ -70,6 +76,7 @@ 6D4D844B1EC7B8E70005932D /* PreferencesInteractorSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4D844A1EC7B8E70005932D /* PreferencesInteractorSpec.swift */; }; 6D5183491EDF4FAF007EC15C /* DateComponentsFormatter+NaturalApproximation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D5183481EDF4FAF007EC15C /* DateComponentsFormatter+NaturalApproximation.swift */; }; 6D51834B1EDF52C6007EC15C /* NaturalApproximationFormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D51834A1EDF52C6007EC15C /* NaturalApproximationFormatterSpec.swift */; }; + 6D5797C41F092B2000AE5D22 /* FileManager+Move.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D5797C31F092B2000AE5D22 /* FileManager+Move.swift */; }; 6D5BB4C51E5915A10006BAE1 /* ApplicationTemporaryFolderEventFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D5BB4C31E5915A10006BAE1 /* ApplicationTemporaryFolderEventFilter.swift */; }; 6D5BB4C61E5915A10006BAE1 /* FolderEventFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D5BB4C41E5915A10006BAE1 /* FolderEventFilter.swift */; }; 6D5BB4C81E598F460006BAE1 /* FolderEventsListenerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D5BB4C71E598F460006BAE1 /* FolderEventsListenerError.swift */; }; @@ -127,6 +134,10 @@ 6DBD6C541EAD4B2B006F14DC /* ApplicationTestLogFilesListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DBD6C531EAD4B2B006F14DC /* ApplicationTestLogFilesListener.swift */; }; 6DBD99D91E7AB31B00E1714E /* NonRecursiveFolderEventsListenerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DBD99D81E7AB31B00E1714E /* NonRecursiveFolderEventsListenerSpec.swift */; }; 6DBD99DB1E7AB3D400E1714E /* FileWatcherFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DBD99DA1E7AB3D400E1714E /* FileWatcherFactory.swift */; }; + 6DCCEF0C1F02F60700523B47 /* SnapshotTestResultSwapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DCCEF0B1F02F60700523B47 /* SnapshotTestResultSwapper.swift */; }; + 6DCCEF0E1F02F64800523B47 /* SnapshotTestResultSwapperSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DCCEF0D1F02F64800523B47 /* SnapshotTestResultSwapperSpec.swift */; }; + 6DD1AEA51F08093E002FCA82 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD1AEA41F08093E002FCA82 /* ImageCache.swift */; }; + 6DD1AEA71F080968002FCA82 /* Nuke+ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD1AEA61F080968002FCA82 /* Nuke+ImageCache.swift */; }; 6DDFBD8D1E63268300DFC0A4 /* FolderEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDFBD8C1E63268300DFC0A4 /* FolderEvent.swift */; }; 6DDFBD911E638EE900DFC0A4 /* MenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDFBD901E638EE900DFC0A4 /* MenuPresenter.swift */; }; 6DDFBDA41E64D14700DFC0A4 /* MenuModuleInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDFBDA31E64D14700DFC0A4 /* MenuModuleInterface.swift */; }; @@ -175,6 +186,12 @@ 6D130B6A1EC8E55F00E9642A /* PreferencesWireframeSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWireframeSpec.swift; sourceTree = ""; }; 6D130B6C1EC8E82B00E9642A /* ConfigurationSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationSpec.swift; sourceTree = ""; }; 6D130B6E1EC8EB2F00E9642A /* PreferencesDisplayInfoSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesDisplayInfoSpec.swift; sourceTree = ""; }; + 6D14776A1EFED5500070EFEC /* BuildCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildCreator.swift; sourceTree = ""; }; + 6D14776C1EFED78D0070EFEC /* BuildCreatorSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildCreatorSpec.swift; sourceTree = ""; }; + 6D14776E1EFEDF5A0070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift; sourceTree = ""; }; + 6D1477701EFEDFED0070EFEC /* FBReferenceImageDirectoryURLExtractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FBReferenceImageDirectoryURLExtractor.swift; sourceTree = ""; }; + 6D1477721EFEE7D00070EFEC /* FBReferenceImageDirectoryURLExtractorSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FBReferenceImageDirectoryURLExtractorSpec.swift; sourceTree = ""; }; + 6D1477741EFEEDB30070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift; sourceTree = ""; }; 6D1C40751EFA628F00D4D5F1 /* Colors+AppleInterfaceMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Colors+AppleInterfaceMode.swift"; sourceTree = ""; }; 6D21E66C1EAE9E3600800B91 /* ApplicationLogReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationLogReader.swift; sourceTree = ""; }; 6D21E66E1EAEAA8A00800B91 /* ApplicationLogReaderSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationLogReaderSpec.swift; sourceTree = ""; }; @@ -226,6 +243,7 @@ 6D4D844A1EC7B8E70005932D /* PreferencesInteractorSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesInteractorSpec.swift; sourceTree = ""; }; 6D5183481EDF4FAF007EC15C /* DateComponentsFormatter+NaturalApproximation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateComponentsFormatter+NaturalApproximation.swift"; sourceTree = ""; }; 6D51834A1EDF52C6007EC15C /* NaturalApproximationFormatterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NaturalApproximationFormatterSpec.swift; sourceTree = ""; }; + 6D5797C31F092B2000AE5D22 /* FileManager+Move.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Move.swift"; sourceTree = ""; }; 6D5BB4C31E5915A10006BAE1 /* ApplicationTemporaryFolderEventFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationTemporaryFolderEventFilter.swift; sourceTree = ""; }; 6D5BB4C41E5915A10006BAE1 /* FolderEventFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FolderEventFilter.swift; sourceTree = ""; }; 6D5BB4C71E598F460006BAE1 /* FolderEventsListenerError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FolderEventsListenerError.swift; sourceTree = ""; }; @@ -282,6 +300,10 @@ 6DBD6C531EAD4B2B006F14DC /* ApplicationTestLogFilesListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationTestLogFilesListener.swift; sourceTree = ""; }; 6DBD99D81E7AB31B00E1714E /* NonRecursiveFolderEventsListenerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NonRecursiveFolderEventsListenerSpec.swift; sourceTree = ""; }; 6DBD99DA1E7AB3D400E1714E /* FileWatcherFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileWatcherFactory.swift; sourceTree = ""; }; + 6DCCEF0B1F02F60700523B47 /* SnapshotTestResultSwapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotTestResultSwapper.swift; sourceTree = ""; }; + 6DCCEF0D1F02F64800523B47 /* SnapshotTestResultSwapperSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotTestResultSwapperSpec.swift; sourceTree = ""; }; + 6DD1AEA41F08093E002FCA82 /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = ""; }; + 6DD1AEA61F080968002FCA82 /* Nuke+ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Nuke+ImageCache.swift"; sourceTree = ""; }; 6DDFBD8C1E63268300DFC0A4 /* FolderEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FolderEvent.swift; sourceTree = ""; }; 6DDFBD901E638EE900DFC0A4 /* MenuPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuPresenter.swift; sourceTree = ""; }; 6DDFBDA31E64D14700DFC0A4 /* MenuModuleInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuModuleInterface.swift; sourceTree = ""; }; @@ -520,6 +542,10 @@ 6D2814811EEDECDA00C4E67C /* TestResultsSectionDisplayInfoSpec.swift */, 6D2814831EEDEE3C00C4E67C /* TestResultsDisplayInfosCollectorSpec.swift */, 6D5BC1D71EF6D1B70003D1CB /* TestResultsDisplayInfoSpec.swift */, + 6D14776C1EFED78D0070EFEC /* BuildCreatorSpec.swift */, + 6D1477721EFEE7D00070EFEC /* FBReferenceImageDirectoryURLExtractorSpec.swift */, + 6D1477741EFEEDB30070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift */, + 6DCCEF0D1F02F64800523B47 /* SnapshotTestResultSwapperSpec.swift */, ); path = FBSnapshotsViewerTests; sourceTree = ""; @@ -575,6 +601,10 @@ 6D3000301EBD2C64005B6103 /* ProcessLauncher.swift */, 6D789CE71EC3C19F00EEF7EE /* ConfigurationStorage.swift */, 6DB94C9C1EE569BA00095C37 /* ApplicationNameExtractor.swift */, + 6D1477701EFEDFED0070EFEC /* FBReferenceImageDirectoryURLExtractor.swift */, + 6D14776A1EFED5500070EFEC /* BuildCreator.swift */, + 6D14776E1EFEDF5A0070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift */, + 6DCCEF0B1F02F60700523B47 /* SnapshotTestResultSwapper.swift */, ); path = Managers; sourceTree = ""; @@ -588,6 +618,7 @@ 6D8BD71E1EB13949004928F7 /* Application.swift */, 6D789CDD1EC3B6CC00EEF7EE /* AutoCases.swift */, 6D3003B11ED20B13000CCAC8 /* Updater.swift */, + 6DD1AEA41F08093E002FCA82 /* ImageCache.swift */, ); path = Protocols; sourceTree = ""; @@ -606,6 +637,8 @@ 6D8BF2BC1ED0B78700C368D1 /* String+HTML.swift */, 6D3003B31ED20B36000CCAC8 /* SUUpdater+Updater.swift */, 6D5183481EDF4FAF007EC15C /* DateComponentsFormatter+NaturalApproximation.swift */, + 6DD1AEA61F080968002FCA82 /* Nuke+ImageCache.swift */, + 6D5797C31F092B2000AE5D22 /* FileManager+Move.swift */, ); path = Extensions; sourceTree = ""; @@ -1001,6 +1034,7 @@ 6D2814781EED7F9300C4E67C /* TestResultsHeader.swift in Sources */, 6D789CE21EC3BE7700EEF7EE /* PreferencesInteractor.swift in Sources */, 6D3000451EBFBE69005B6103 /* PreferencesUserInterface.swift in Sources */, + 6D14776F1EFEDF5A0070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift in Sources */, 6D5F91381E4F6D3500C6E5BF /* FolderEventsListener.swift in Sources */, 6D848C631E6964D90000FC1E /* TestResultsCollectionViewOutlets.swift in Sources */, 6DE3477A1E47D917004147DF /* MenuUserInterface.swift in Sources */, @@ -1029,8 +1063,10 @@ 6D5BB4C51E5915A10006BAE1 /* ApplicationTemporaryFolderEventFilter.swift in Sources */, 6D28147E1EED9E4100C4E67C /* TestResultsDisplayInfosCollector.swift in Sources */, 6D848C5D1E68D6A50000FC1E /* TestResultsInteractor.swift in Sources */, + 6D14776B1EFED5500070EFEC /* BuildCreator.swift in Sources */, 6D8362771E79422D000794AE /* AutoEquatable.swift in Sources */, 6D5F91391E4F6D3500C6E5BF /* NonRecursiveFolderEventsListener.swift in Sources */, + 6D1477711EFEDFED0070EFEC /* FBReferenceImageDirectoryURLExtractor.swift in Sources */, 6D3000491EBFBE97005B6103 /* PreferencesModuleInterface.swift in Sources */, 6DDFBD911E638EE900DFC0A4 /* MenuPresenter.swift in Sources */, 6D33A9D61EB4DB650089AEDD /* AutoHashable.generated.swift in Sources */, @@ -1047,10 +1083,12 @@ 6D848C611E68D7B80000FC1E /* TestResultsPresenter.swift in Sources */, 6DE347781E47D8E5004147DF /* MenuWireframe.swift in Sources */, 6D3BA5741E6E158100CAD4EE /* AutoMockable.generated.swift in Sources */, + 6DD1AEA51F08093E002FCA82 /* ImageCache.swift in Sources */, 6D848C5B1E68D5720000FC1E /* TestResultsInteractorIO.swift in Sources */, 6D3000431EBFBE14005B6103 /* PreferencesController.swift in Sources */, 6D5F913C1E4F6D4700C6E5BF /* FolderEventsListenerFactory.swift in Sources */, 6D89B9541EF088B600865C5F /* TestResultsDiffMode.swift in Sources */, + 6DCCEF0C1F02F60700523B47 /* SnapshotTestResultSwapper.swift in Sources */, 6DA1BF991E7755110017D47B /* Storyboards.swift in Sources */, 6DE3477E1E47D9DF004147DF /* MenuInteractorIO.swift in Sources */, 6DBD6C501EACF1B0006F14DC /* DerivedDataFolder.swift in Sources */, @@ -1061,6 +1099,7 @@ 6DF15B751E662CBD00DFA181 /* TestResultsController.swift in Sources */, 6D3000471EBFBE86005B6103 /* PreferencesWireframe.swift in Sources */, 6DA1BF981E7755110017D47B /* Colors.swift in Sources */, + 6D5797C41F092B2000AE5D22 /* FileManager+Move.swift in Sources */, 6D789CE61EC3BFA900EEF7EE /* Configuration.swift in Sources */, 6DBD99DB1E7AB3D400E1714E /* FileWatcherFactory.swift in Sources */, 6D9EF95C1EF5DBD600AA15B1 /* TestResultsDisplayInfo.swift in Sources */, @@ -1073,6 +1112,7 @@ 6D789CD81EC3B07A00EEF7EE /* PreferencesDisplayInfo.swift in Sources */, 6DF15B771E662CCC00DFA181 /* TestResultsUserInterface.swift in Sources */, 6D848C561E68D0C90000FC1E /* TestResultCell.swift in Sources */, + 6DD1AEA71F080968002FCA82 /* Nuke+ImageCache.swift in Sources */, 6D30002B1EBD242E005B6103 /* ExternalViewer.swift in Sources */, 6D789CDE1EC3B6CC00EEF7EE /* AutoCases.swift in Sources */, ); @@ -1083,6 +1123,7 @@ buildActionMask = 2147483647; files = ( 6D3000351EBD325D005B6103 /* OSXApplicationFinderSpec.swift in Sources */, + 6D1477751EFEEDB30070EFEC /* ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift in Sources */, 6D30003C1EBF29D8005B6103 /* TestResultCellSpec.swift in Sources */, 6D130B6F1EC8EB2F00E9642A /* PreferencesDisplayInfoSpec.swift in Sources */, 6D33A9D81EB4E0AD0089AEDD /* ApplicationLogLineSpec.swift in Sources */, @@ -1090,6 +1131,7 @@ 6D21F7481E6CBAFA00BFCE4C /* MenuControllerSpec.swift in Sources */, 6D8BF2BF1ED0CCD600C368D1 /* StringHTMLSpec.swift in Sources */, 6D12F4611E8086F000AA4727 /* TestResultsWireframeSpec.swift in Sources */, + 6D14776D1EFED78D0070EFEC /* BuildCreatorSpec.swift in Sources */, 6D076B7B1E7F3177001FDA14 /* TestResultsPresenterSpec.swift in Sources */, 6D92E1CB1E730A5C00DB73C7 /* MenuInteractorSpec.swift in Sources */, 6D076B771E7EBD15001FDA14 /* TestResultDisplayInfoSpec.swift in Sources */, @@ -1097,8 +1139,10 @@ 6D3000331EBD2DB3005B6103 /* KaleidoscopeViewerSpec.swift in Sources */, 6D42C9401EB27B64003744BF /* SnapshotTestResultFactorySpec.swift in Sources */, 6DE3475E1E476F8A004147DF /* FolderEventSpec.swift in Sources */, + 6D1477731EFEE7D00070EFEC /* FBReferenceImageDirectoryURLExtractorSpec.swift in Sources */, 6D130B6D1EC8E82B00E9642A /* ConfigurationSpec.swift in Sources */, 6D3BA5651E6E07AA00CAD4EE /* MenuPresenterSpec.swift in Sources */, + 6DCCEF0E1F02F64800523B47 /* SnapshotTestResultSwapperSpec.swift in Sources */, 6D42C93E1EB275B6003744BF /* MenuWireframeSpec.swift in Sources */, 6D342CE21EBBDFDF006EEBEC /* AppleInterfaceModeSpec.swift in Sources */, 6D12F4721E81758500AA4727 /* TestResultsControllerSpec.swift in Sources */, diff --git a/FBSnapshotsViewer/AppDelegate.swift b/FBSnapshotsViewer/AppDelegate.swift index 9c1cf23..3f959ea 100644 --- a/FBSnapshotsViewer/AppDelegate.swift +++ b/FBSnapshotsViewer/AppDelegate.swift @@ -22,8 +22,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { let wireframe = MenuWireframe() menuUserInterface = wireframe.instantinateMenu(in: NSStatusBar.system(), configuration: cofiguration) } - - func setUpConfiguration() -> Configuration { + + // MARK: - Helpers + + private func setUpConfiguration() -> Configuration { let configurationStorage = UserDefaultsConfigurationStorage() if let configuration = configurationStorage.loadConfiguration() { print("App already has configuration stored") diff --git a/FBSnapshotsViewer/Extensions/FileManager+Move.swift b/FBSnapshotsViewer/Extensions/FileManager+Move.swift new file mode 100644 index 0000000..76f8080 --- /dev/null +++ b/FBSnapshotsViewer/Extensions/FileManager+Move.swift @@ -0,0 +1,16 @@ +// +// FileManager+Move.swift +// FBSnapshotsViewer +// +// Created by Anton Domashnev on 02.07.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Foundation + +extension FileManager { + func moveItem(at fromURL: URL, to toURL: URL) throws { + try self.removeItem(at: toURL) + try self.copyItem(at: fromURL, to: toURL) + } +} diff --git a/FBSnapshotsViewer/Extensions/Nuke+ImageCache.swift b/FBSnapshotsViewer/Extensions/Nuke+ImageCache.swift new file mode 100644 index 0000000..14d8f50 --- /dev/null +++ b/FBSnapshotsViewer/Extensions/Nuke+ImageCache.swift @@ -0,0 +1,15 @@ +// +// Nuke+ImageCache.swift +// FBSnapshotsViewer +// +// Created by Anton Domashnev on 01.07.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Nuke + +extension Nuke.Cache: ImageCache { + func invalidate() { + self.removeAll() + } +} diff --git a/FBSnapshotsViewer/Listeners/ApplicationSnapshotTestResultListener.swift b/FBSnapshotsViewer/Listeners/ApplicationSnapshotTestResultListener.swift index 331715b..f43200a 100644 --- a/FBSnapshotsViewer/Listeners/ApplicationSnapshotTestResultListener.swift +++ b/FBSnapshotsViewer/Listeners/ApplicationSnapshotTestResultListener.swift @@ -12,19 +12,14 @@ import KZFileWatchers typealias ApplicationSnapshotTestResultListenerOutput = (SnapshotTestResult) -> Void class ApplicationSnapshotTestResultListener { - private var build: Build? - private var readLinesNumber: Int = 0 private var listeningOutput: ApplicationSnapshotTestResultListenerOutput? private let fileWatcher: KZFileWatchers.FileWatcherProtocol - private let applicationLogReader: ApplicationLogReader - private let snapshotTestResultFactory: SnapshotTestResultFactory - private let applicationNameExtractor: ApplicationNameExtractor + private let fileWatcherUpdateHandler: ApplicationSnapshotTestResultFileWatcherUpdateHandler - init(fileWatcher: KZFileWatchers.FileWatcherProtocol, applicationLogReader: ApplicationLogReader, applicationNameExtractor: ApplicationNameExtractor, snapshotTestResultFactory: SnapshotTestResultFactory = SnapshotTestResultFactory()) { + init(fileWatcher: KZFileWatchers.FileWatcherProtocol, + fileWatcherUpdateHandler: ApplicationSnapshotTestResultFileWatcherUpdateHandler) { self.fileWatcher = fileWatcher - self.applicationLogReader = applicationLogReader - self.snapshotTestResultFactory = snapshotTestResultFactory - self.applicationNameExtractor = applicationNameExtractor + self.fileWatcherUpdateHandler = fileWatcherUpdateHandler } deinit { @@ -36,7 +31,12 @@ class ApplicationSnapshotTestResultListener { listeningOutput = completion do { try fileWatcher.start { [weak self] result in - self?.handleFileWatcherUpdate(result: result) + guard let listeningOutput = self?.listeningOutput, + let testResults = self?.fileWatcherUpdateHandler.handleFileWatcherUpdate(result: result), + !testResults.isEmpty else { + return + } + testResults.forEach { listeningOutput($0) } } } catch let error { @@ -55,54 +55,8 @@ class ApplicationSnapshotTestResultListener { reset() } - // MARK: - Helpers - - private func handleFileWatcherUpdate(result: KZFileWatchers.FileWatcher.RefreshResult) { - switch result { - case .noChanges: - return - case let .updated(data): - guard let text = String(data: data, encoding: .utf8), !text.isEmpty else { - assertionFailure("Invalid data reported by KZFileWatchers.FileWatcher.Local") - return - } - do { - try handleFileWatcherUpdate(text: text) - } - catch let error { - assertionFailure("\(error)") - } - } - } - - private func handleFileWatcherUpdate(text: String) throws { - guard let listeningOutput = listeningOutput else { - return - } - let logLines = applicationLogReader.readline(of: text, startingFrom: readLinesNumber) - let snapshotTestResults = try logLines.flatMap { logLine -> SnapshotTestResult? in - switch logLine { - case .unknown: - return nil - case .applicationNameMessage: - build = Build(applicationName: try applicationNameExtractor.extractApplicationName(from: logLine)) - return nil - default: - guard let build = build else { - assertionFailure("Unexpected snapshot test result line \(logLine) before build information line") - return nil - } - return snapshotTestResultFactory.createSnapshotTestResult(from: logLine, build: build) - } - } - snapshotTestResults.forEach { listeningOutput($0) } - readLinesNumber += logLines.count - } - private func reset() { - readLinesNumber = 0 listeningOutput = nil - build = nil try? fileWatcher.stop() } } diff --git a/FBSnapshotsViewer/Managers/ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift b/FBSnapshotsViewer/Managers/ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift new file mode 100644 index 0000000..e229f3d --- /dev/null +++ b/FBSnapshotsViewer/Managers/ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift @@ -0,0 +1,96 @@ +// +// ApplicationSnapshotTestResultFileWatcherUpdateHandler.swift +// FBSnapshotsViewer +// +// Created by Anton Domashnev on 24.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Foundation +import KZFileWatchers + +class ApplicationSnapshotTestResultFileWatcherUpdateHandlerBuilder { + var applicationLogReader: ApplicationLogReader = ApplicationLogReader() + var snapshotTestResultFactory: SnapshotTestResultFactory = SnapshotTestResultFactory() + var applicationNameExtractor: ApplicationNameExtractor = XcodeApplicationNameExtractor() + var fbImageReferenceDirExtractor: FBReferenceImageDirectoryURLExtractor = XcodeFBReferenceImageDirectoryURLExtractor() + var buildCreator: BuildCreator = BuildCreator() + + typealias BuilderClojure = (ApplicationSnapshotTestResultFileWatcherUpdateHandlerBuilder) -> Void + + init(clojure: BuilderClojure) { + clojure(self) + } +} + +class ApplicationSnapshotTestResultFileWatcherUpdateHandler { + private let applicationLogReader: ApplicationLogReader + private let snapshotTestResultFactory: SnapshotTestResultFactory + private let applicationNameExtractor: ApplicationNameExtractor + private let fbImageReferenceDirExtractor: FBReferenceImageDirectoryURLExtractor + private let buildCreator: BuildCreator + private var readLinesNumber: Int = 0 + + init(builder: ApplicationSnapshotTestResultFileWatcherUpdateHandlerBuilder = ApplicationSnapshotTestResultFileWatcherUpdateHandlerBuilder(clojure: { _ in })) { + self.applicationLogReader = builder.applicationLogReader + self.snapshotTestResultFactory = builder.snapshotTestResultFactory + self.applicationNameExtractor = builder.applicationNameExtractor + self.buildCreator = builder.buildCreator + self.fbImageReferenceDirExtractor = builder.fbImageReferenceDirExtractor + } + + // MARK: - Interface + + @discardableResult func handleFileWatcherUpdate(result: KZFileWatchers.FileWatcher.RefreshResult) -> [SnapshotTestResult] { + switch result { + case .noChanges: + return [] + case let .updated(data): + guard let text = String(data: data, encoding: .utf8), !text.isEmpty else { + assertionFailure("Invalid data reported by KZFileWatchers.FileWatcher.Local") + return [] + } + do { + return try handleFileWatcherUpdate(text: text) ?? [] + } + catch let error { + assertionFailure("\(error)") + return [] + } + } + } + + // MARK: - Helpers + + private func logLinesFlatMap() -> (ApplicationLogLine) throws -> SnapshotTestResult? { + return { [weak self] logLine -> SnapshotTestResult? in + guard let strongSelf = self else { + return nil + } + switch logLine { + case .unknown: + return nil + case .fbReferenceImageDirMessage: + strongSelf.buildCreator.fbReferenceImageDirectoryURL = try strongSelf.fbImageReferenceDirExtractor.extractImageDirectoryURL(from: logLine) + return nil + case .applicationNameMessage: + strongSelf.buildCreator.applicationName = try strongSelf.applicationNameExtractor.extractApplicationName(from: logLine) + strongSelf.buildCreator.date = Date() + return nil + default: + guard let build = strongSelf.buildCreator.createBuild() else { + assertionFailure("Unexpected snapshot test result line \(logLine) before build information line") + return nil + } + return strongSelf.snapshotTestResultFactory.createSnapshotTestResult(from: logLine, build: build) + } + } + } + + private func handleFileWatcherUpdate(text: String) throws -> [SnapshotTestResult]? { + let logLines = applicationLogReader.readline(of: text, startingFrom: readLinesNumber) + let snapshotTestResults = try logLines.flatMap(logLinesFlatMap()) + readLinesNumber += logLines.count + return snapshotTestResults + } +} diff --git a/FBSnapshotsViewer/Managers/ApplicationSnapshotTestResultListenerFactory.swift b/FBSnapshotsViewer/Managers/ApplicationSnapshotTestResultListenerFactory.swift index 4346e48..16fab2c 100644 --- a/FBSnapshotsViewer/Managers/ApplicationSnapshotTestResultListenerFactory.swift +++ b/FBSnapshotsViewer/Managers/ApplicationSnapshotTestResultListenerFactory.swift @@ -11,17 +11,26 @@ import KZFileWatchers class ApplicationSnapshotTestResultListenerFactory { private let applicationNameExtractorFactory: ApplicationNameExtractorFactory + private let fbReferenceImageDirExtractorFactory: FBReferenceImageDirectoryURLExtractorFactory // MARK: - Interface - init(applicationNameExtractorFactory: ApplicationNameExtractorFactory = ApplicationNameExtractorFactory()) { + init(applicationNameExtractorFactory: ApplicationNameExtractorFactory = ApplicationNameExtractorFactory(), fbReferenceImageDirExtractorFactory: FBReferenceImageDirectoryURLExtractorFactory = FBReferenceImageDirectoryURLExtractorFactory()) { self.applicationNameExtractorFactory = applicationNameExtractorFactory + self.fbReferenceImageDirExtractorFactory = fbReferenceImageDirExtractorFactory } func applicationSnapshotTestResultListener(forLogFileAt path: String, configuration: Configuration = Configuration.default()) -> ApplicationSnapshotTestResultListener { let fileWatcher = KZFileWatchers.FileWatcher.Local(path: path) let reader = ApplicationLogReader(configuration: configuration) let applicationNameExtractor = applicationNameExtractorFactory.applicationNameExtractor(for: configuration) - return ApplicationSnapshotTestResultListener(fileWatcher: fileWatcher, applicationLogReader: reader, applicationNameExtractor: applicationNameExtractor) + let imageDirectoryExtractor = fbReferenceImageDirExtractorFactory.fbReferenceImageDirectoryURLExtractor(for: configuration) + let builder = ApplicationSnapshotTestResultFileWatcherUpdateHandlerBuilder { + $0.applicationLogReader = reader + $0.applicationNameExtractor = applicationNameExtractor + $0.fbImageReferenceDirExtractor = imageDirectoryExtractor + } + let applicationSnapshotTestResultFileWatcherUpdateHandler = ApplicationSnapshotTestResultFileWatcherUpdateHandler(builder: builder) + return ApplicationSnapshotTestResultListener(fileWatcher: fileWatcher, fileWatcherUpdateHandler: applicationSnapshotTestResultFileWatcherUpdateHandler) } } diff --git a/FBSnapshotsViewer/Managers/BuildCreator.swift b/FBSnapshotsViewer/Managers/BuildCreator.swift new file mode 100644 index 0000000..7668b17 --- /dev/null +++ b/FBSnapshotsViewer/Managers/BuildCreator.swift @@ -0,0 +1,23 @@ +// +// BuildCreator.swift +// FBSnapshotsViewer +// +// Created by Anton Domashnev on 24.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Foundation + +class BuildCreator { + var date: Date? + var applicationName: String? + var fbReferenceImageDirectoryURL: URL? + + func createBuild() -> Build? { + guard let date = date, let applicationName = applicationName, let fbReferenceImageDirectoryURL = fbReferenceImageDirectoryURL else { + print("Can not create a build if not all require properties are initialized:\ndate: \(String(describing: self.date))\napplicationName: \(String(describing: self.applicationName))\nfbReferenceImageDirectoryURL: \(String(describing: self.fbReferenceImageDirectoryURL))") + return nil + } + return Build(date: date, applicationName: applicationName, fbReferenceImageDirectoryURL: fbReferenceImageDirectoryURL) + } +} diff --git a/FBSnapshotsViewer/Managers/FBReferenceImageDirectoryURLExtractor.swift b/FBSnapshotsViewer/Managers/FBReferenceImageDirectoryURLExtractor.swift new file mode 100644 index 0000000..eddcf0d --- /dev/null +++ b/FBSnapshotsViewer/Managers/FBReferenceImageDirectoryURLExtractor.swift @@ -0,0 +1,66 @@ +// +// FBReferenceImageDirectoryURLExtractor.swift +// FBSnapshotsViewer +// +// Created by Anton Domashnev on 24.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Foundation + +enum FBReferenceImageDirectoryURLExtractorError: Error { + case unexpectedLogLine(message: String) +} + +protocol FBReferenceImageDirectoryURLExtractor: AutoMockable { + func extractImageDirectoryURL(from logLine: ApplicationLogLine) throws -> URL +} + +class FBReferenceImageDirectoryURLExtractorFactory { + func fbReferenceImageDirectoryURLExtractor(for configuration: Configuration) -> FBReferenceImageDirectoryURLExtractor { + switch configuration.derivedDataFolder { + case .xcodeCustom, + .xcodeDefault: + return XcodeFBReferenceImageDirectoryURLExtractor() + case .appcode: + return AppCodeFBReferenceImageDirectoryURLExtractor() + } + } +} + +class FBReferenceImageDirectoryURLExtractorHelper { + static func buildReferenceImagePathURL(with path: String) -> URL { + // ios-snapshots adds a suffix for the reference dir depending on the acrhitecture. For now we support only 64 bit + return URL(fileURLWithPath: path + "_64", isDirectory: true) + } + + static func extractLine(from logLine: ApplicationLogLine) throws -> String { + guard case let .fbReferenceImageDirMessage(line) = logLine, + line.contains("/") else { + throw FBReferenceImageDirectoryURLExtractorError.unexpectedLogLine(message: "Unexpected log line given: \(logLine). Expected .fbReferenceImageDirMessage") + } + return line + } + + static func extractImageDirectoryURL(from logLine: ApplicationLogLine, componentsBuilder: (String) -> [String]?, expectedLogLineExample: String) throws -> URL { + let line = try extractLine(from: logLine) + guard let components = componentsBuilder(line), components.count == 3 else { + throw FBReferenceImageDirectoryURLExtractorError.unexpectedLogLine(message: "Unexpected log line given: \(logLine). Expected the following format: \(expectedLogLineExample)") + } + return buildReferenceImagePathURL(with: components[1]) + } +} + +class XcodeFBReferenceImageDirectoryURLExtractor: FBReferenceImageDirectoryURLExtractor { + func extractImageDirectoryURL(from logLine: ApplicationLogLine) throws -> URL { + let componentsBuilder: (String) -> [String]? = { $0.components(separatedBy: " = ").last?.components(separatedBy: "\"") } + return try FBReferenceImageDirectoryURLExtractorHelper.extractImageDirectoryURL(from: logLine, componentsBuilder: componentsBuilder, expectedLogLineExample: "\"FB_REFERENCE_IMAGE_DIR\" = \"/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages\";") + } +} + +class AppCodeFBReferenceImageDirectoryURLExtractor: FBReferenceImageDirectoryURLExtractor { + func extractImageDirectoryURL(from logLine: ApplicationLogLine) throws -> URL { + let componentsBuilder: (String) -> [String]? = { $0.components(separatedBy: "value=").last?.components(separatedBy: "\"") } + return try FBReferenceImageDirectoryURLExtractorHelper.extractImageDirectoryURL(from: logLine, componentsBuilder: componentsBuilder, expectedLogLineExample: "") + } +} diff --git a/FBSnapshotsViewer/Managers/SnapshotTestResultFactory.swift b/FBSnapshotsViewer/Managers/SnapshotTestResultFactory.swift index d11124d..1163b0f 100644 --- a/FBSnapshotsViewer/Managers/SnapshotTestResultFactory.swift +++ b/FBSnapshotsViewer/Managers/SnapshotTestResultFactory.swift @@ -16,7 +16,7 @@ enum SnapshotTestResultFactoryError: Error { class SnapshotTestResultFactory { // MARK: - Helpers - private func extractTestName(fromFailedImage path: String) throws -> String { + private func extractTestInformation(fromFailedImage path: String) throws -> SnapshotTestInformation { let pathComponents = path.components(separatedBy: "/") guard pathComponents.count >= 2, let testName = pathComponents.last?.components(separatedBy: "failed_").last?.components(separatedBy: "@").first, @@ -24,10 +24,10 @@ class SnapshotTestResultFactory { throw SnapshotTestResultFactoryError.unexpectedKaleidoscopeCommandLineFormat } let testClassName = pathComponents[pathComponents.count - 2] - return "\(testClassName) \(testName)" + return SnapshotTestInformation(testClassName: testClassName, testName: testName) } - private func extractTestName(fromSavedReferenceImage path: String) throws -> String { + private func extractTestInformation(fromSavedReferenceImage path: String) throws -> SnapshotTestInformation { let pathComponents = path.components(separatedBy: "/") guard pathComponents.count >= 2, let testName = pathComponents.last?.components(separatedBy: "@").first, @@ -35,7 +35,7 @@ class SnapshotTestResultFactory { throw SnapshotTestResultFactoryError.unexpectedSavedReferenceImageLineFormat } let testClassName = pathComponents[pathComponents.count - 2] - return "\(testClassName) \(testName)" + return SnapshotTestInformation(testClassName: testClassName, testName: testName) } private func createSnapshotTestResult(fromKaleidoscopeCommandLine line: String, build: Build) throws -> SnapshotTestResult { @@ -46,27 +46,27 @@ class SnapshotTestResultFactory { let referenceImagePath = lineComponents[1] let failedImagePath = lineComponents[3] let diffImagePath = failedImagePath.replacingOccurrences(of: "/failed_", with: "/diff_") - let testName = try extractTestName(fromFailedImage: failedImagePath) - return SnapshotTestResult.failed(testName: testName, referenceImagePath: referenceImagePath, diffImagePath: diffImagePath, failedImagePath: failedImagePath, build: build) + let testInformation = try extractTestInformation(fromFailedImage: failedImagePath) + return SnapshotTestResult.failed(testInformation: testInformation, referenceImagePath: referenceImagePath, diffImagePath: diffImagePath, failedImagePath: failedImagePath, build: build) } private func createSnapshotTestResult(fromSavedReferenceImageLine line: String, build: Build) throws -> SnapshotTestResult { - let lineComponents = line.components(separatedBy: ApplicationLogLine.referenceImageSavedMessageIndicatorSubstring) + let lineComponents = line.components(separatedBy: ": ") guard lineComponents.count == 2 else { throw SnapshotTestResultFactoryError.unexpectedSavedReferenceImageLineFormat } let referenceImagePath = lineComponents[1] - let testName = try extractTestName(fromSavedReferenceImage: referenceImagePath) - return SnapshotTestResult.recorded(testName: testName, referenceImagePath: referenceImagePath, build: build) + let testInformation = try extractTestInformation(fromSavedReferenceImage: referenceImagePath) + return SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: referenceImagePath, build: build) } // MARK: - Interface func createSnapshotTestResult(from logLine: ApplicationLogLine, build: Build) -> SnapshotTestResult? { switch logLine { - case .unknown: - return nil - case .applicationNameMessage: + case .unknown, + .applicationNameMessage, + .fbReferenceImageDirMessage: return nil case let .kaleidoscopeCommandMessage(line): return try? self.createSnapshotTestResult(fromKaleidoscopeCommandLine: line, build: build) diff --git a/FBSnapshotsViewer/Managers/SnapshotTestResultSwapper.swift b/FBSnapshotsViewer/Managers/SnapshotTestResultSwapper.swift new file mode 100644 index 0000000..49f2470 --- /dev/null +++ b/FBSnapshotsViewer/Managers/SnapshotTestResultSwapper.swift @@ -0,0 +1,62 @@ +// +// SnapshotTestResultSwapper.swift +// FBSnapshotsViewer +// +// Created by Anton Domashnev on 27.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Foundation +import Nuke + +enum SnapshotTestResultSwapperError: Error { + case canNotBeSwapped(testResult: SnapshotTestResult) + case nonRetinaImages(testResult: SnapshotTestResult) + case canNotPerformFileManagerOperation(testResult: SnapshotTestResult, underlyingError: Error) +} + +class SnapshotTestResultSwapper { + private let fileManager: FileManager + private let imageCache: ImageCache + + init(fileManager: FileManager = FileManager.default, imageCache: ImageCache = Nuke.Cache.shared) { + self.imageCache = imageCache + self.fileManager = fileManager + } + + // MARK: - Helpers + + private func buildRecordedImageURL(from imagePath: String, of testResult: SnapshotTestResult) throws -> URL { + guard let failedImageSizeSuffixRange = imagePath.range(of: "@\\d{1}x", options: .regularExpression) else { + throw SnapshotTestResultSwapperError.nonRetinaImages(testResult: testResult) + } + let failedImageSizeSuffix = imagePath.substring(with: failedImageSizeSuffixRange) + let recordedImageURL = testResult.build.fbReferenceImageDirectoryURL.appendingPathComponent(testResult.testClassName).appendingPathComponent("\(testResult.testName)\(failedImageSizeSuffix)").appendingPathExtension("png") + return recordedImageURL + } + + // MARK: - Interface + + func canSwap(_ testResult: SnapshotTestResult) -> Bool { + if case SnapshotTestResult.failed(_, _, _, _, _) = testResult { + return true + } + return false + } + + func swap(_ testResult: SnapshotTestResult) throws -> SnapshotTestResult { + guard case let SnapshotTestResult.failed(testInformation, _, _, failedImagePath, build) = testResult, canSwap(testResult) else { + throw SnapshotTestResultSwapperError.canNotBeSwapped(testResult: testResult) + } + let failedImageURL = URL(fileURLWithPath: failedImagePath, isDirectory: false) + do { + let recordedImageURL = try buildRecordedImageURL(from: failedImagePath, of: testResult) + try fileManager.moveItem(at: failedImageURL, to: recordedImageURL) + imageCache.invalidate() + return SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: recordedImageURL.path, build: build) + } + catch let error { + throw SnapshotTestResultSwapperError.canNotPerformFileManagerOperation(testResult: testResult, underlyingError: error) + } + } +} diff --git a/FBSnapshotsViewer/Models/ApplicationLogLine.swift b/FBSnapshotsViewer/Models/ApplicationLogLine.swift index bb5cae2..971a799 100644 --- a/FBSnapshotsViewer/Models/ApplicationLogLine.swift +++ b/FBSnapshotsViewer/Models/ApplicationLogLine.swift @@ -26,16 +26,19 @@ struct ApplicationLogLineIndicatorContainer { return "PROJECT_NAME=" } } + + static func fbReferenceImageDirMessageIndicator(for configuration: Configuration = Configuration.default()) -> String { + return "FB_REFERENCE_IMAGE_DIR" + } } enum ApplicationLogLine: AutoEquatable, AutoHashable { - static let kaleidoscopeCommandMessageIndicatorSubstring = "ksdiff " - static let referenceImageSavedMessageIndicatorSubstring = "Reference image save at: " - static let applicationNameMessageIndicatorSubstring = "XCInjectBundleInto" + static let fbReferenceImageDirMessageIndicatorSubstring = "FB_REFERENCE_IMAGE_DIR" case kaleidoscopeCommandMessage(line: String) case referenceImageSavedMessage(line: String) case applicationNameMessage(line: String) + case fbReferenceImageDirMessage(line: String) case unknown init(line: String, configuration: Configuration = Configuration.default()) { @@ -48,6 +51,9 @@ enum ApplicationLogLine: AutoEquatable, AutoHashable { else if line.contains(ApplicationLogLineIndicatorContainer.applicationNameMessageIndicator(for: configuration)) { self = ApplicationLogLine.applicationNameMessage(line: line) } + else if line.contains(ApplicationLogLineIndicatorContainer.fbReferenceImageDirMessageIndicator(for: configuration)) { + self = ApplicationLogLine.fbReferenceImageDirMessage(line: line) + } else { self = ApplicationLogLine.unknown } diff --git a/FBSnapshotsViewer/Models/Build.swift b/FBSnapshotsViewer/Models/Build.swift index 03edb59..9d4f19b 100644 --- a/FBSnapshotsViewer/Models/Build.swift +++ b/FBSnapshotsViewer/Models/Build.swift @@ -11,14 +11,11 @@ import Foundation struct Build: AutoHashable, AutoEquatable { let date: Date let applicationName: String + let fbReferenceImageDirectoryURL: URL - init(date: Date, applicationName: String) { + init(date: Date, applicationName: String, fbReferenceImageDirectoryURL: URL) { self.applicationName = applicationName self.date = date - } - - init(applicationName: String) { - self.date = Date() - self.applicationName = applicationName + self.fbReferenceImageDirectoryURL = fbReferenceImageDirectoryURL } } diff --git a/FBSnapshotsViewer/Models/SnapshotTestResult.swift b/FBSnapshotsViewer/Models/SnapshotTestResult.swift index 8435568..e9e87cf 100644 --- a/FBSnapshotsViewer/Models/SnapshotTestResult.swift +++ b/FBSnapshotsViewer/Models/SnapshotTestResult.swift @@ -8,16 +8,34 @@ import Cocoa +struct SnapshotTestInformation: AutoEquatable { + let testClassName: String + let testName: String + + init(testClassName: String, testName: String) { + self.testClassName = testClassName + self.testName = testName + } +} + enum SnapshotTestResult: AutoEquatable { + var testClassName: String { + return testInformation.testClassName + } + var testName: String { + return testInformation.testName + } + + var testInformation: SnapshotTestInformation { switch self { - case let .recorded(testName, _, _): - return testName - case let .failed(testName, _, _, _, _): - return testName + case let .recorded(testInformation, _, _): + return testInformation + case let .failed(testInformation, _, _, _, _): + return testInformation } } - + var build: Build { switch self { case let .recorded(_, _, build): @@ -27,11 +45,11 @@ enum SnapshotTestResult: AutoEquatable { } } - case recorded(testName: String, + case recorded(testInformation: SnapshotTestInformation, referenceImagePath: String, build: Build) - case failed(testName: String, + case failed(testInformation: SnapshotTestInformation, referenceImagePath: String, diffImagePath: String, failedImagePath: String, diff --git a/FBSnapshotsViewer/Protocols/ImageCache.swift b/FBSnapshotsViewer/Protocols/ImageCache.swift new file mode 100644 index 0000000..412a8e1 --- /dev/null +++ b/FBSnapshotsViewer/Protocols/ImageCache.swift @@ -0,0 +1,13 @@ +// +// ImageCache.swift +// FBSnapshotsViewer +// +// Created by Anton Domashnev on 01.07.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Foundation + +protocol ImageCache: AutoMockable { + func invalidate() +} diff --git a/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractor.swift b/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractor.swift index 667e709..95830c4 100644 --- a/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractor.swift +++ b/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractor.swift @@ -8,19 +8,49 @@ import Foundation +enum TestResultsInteractorError: Error { + case canNotSwapNotExistedTestResult +} + +class TestResultsInteractorBuilder { + var kaleidoscopeViewer: ExternalViewer.Type = KaleidoscopeViewer.self + var processLauncher: ProcessLauncher = ProcessLauncher() + var swapper: SnapshotTestResultSwapper = SnapshotTestResultSwapper() + var testResults: [SnapshotTestResult] = [] + + typealias BuiderClojure = (TestResultsInteractorBuilder) -> Void + + init(clojure: BuiderClojure) { + clojure(self) + } +} + class TestResultsInteractor { fileprivate let kaleidoscopeViewer: ExternalViewer.Type fileprivate let processLauncher: ProcessLauncher - let testResults: [SnapshotTestResult] + fileprivate let swapper: SnapshotTestResultSwapper + var testResults: [SnapshotTestResult] + + weak var output: TestResultsInteractorOutput? - init(testResults: [SnapshotTestResult], kaleidoscopeViewer: ExternalViewer.Type = KaleidoscopeViewer.self, processLauncher: ProcessLauncher = ProcessLauncher()) { - self.testResults = testResults - self.kaleidoscopeViewer = kaleidoscopeViewer - self.processLauncher = processLauncher + init(builder: TestResultsInteractorBuilder) { + self.testResults = builder.testResults + self.kaleidoscopeViewer = builder.kaleidoscopeViewer + self.processLauncher = builder.processLauncher + self.swapper = builder.swapper } } extension TestResultsInteractor: TestResultsInteractorInput { + // MARK: - Helpers + + private func replace(testResult: SnapshotTestResult, with newTestResult: SnapshotTestResult) throws { + guard let indexOfTestResult = testResults.index(of: testResult) else { + throw TestResultsInteractorError.canNotSwapNotExistedTestResult + } + testResults[indexOfTestResult] = newTestResult + } + // MARK: - TestResultsInteractorInput func openInKaleidoscope(testResult: SnapshotTestResult) { @@ -30,4 +60,17 @@ extension TestResultsInteractor: TestResultsInteractorInput { } kaleidoscopeViewer.view(snapshotTestResult: testResult, using: processLauncher) } + + func swap(testResult: SnapshotTestResult) { + if !swapper.canSwap(testResult) { + return + } + do { + let swappedTestResult = try swapper.swap(testResult) + try replace(testResult: testResult, with: swappedTestResult) + } + catch let error { + output?.didFailToSwap(testResult: testResult, with: error) + } + } } diff --git a/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractorIO.swift b/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractorIO.swift index e3ac81a..e89e448 100644 --- a/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractorIO.swift +++ b/FBSnapshotsViewer/Test Results/Interactor/TestResultsInteractorIO.swift @@ -11,4 +11,9 @@ import Cocoa protocol TestResultsInteractorInput: class, AutoMockable { var testResults: [SnapshotTestResult] { get } func openInKaleidoscope(testResult: SnapshotTestResult) + func swap(testResult: SnapshotTestResult) +} + +protocol TestResultsInteractorOutput: class, AutoMockable { + func didFailToSwap(testResult: SnapshotTestResult, with error: Error) } diff --git a/FBSnapshotsViewer/Test Results/Presenter/TestResultDisplayInfo.swift b/FBSnapshotsViewer/Test Results/Presenter/TestResultDisplayInfo.swift index 40d0158..53e3652 100644 --- a/FBSnapshotsViewer/Test Results/Presenter/TestResultDisplayInfo.swift +++ b/FBSnapshotsViewer/Test Results/Presenter/TestResultDisplayInfo.swift @@ -15,10 +15,12 @@ struct TestResultDisplayInfo: AutoEquatable { let testName: String let testContext: String let canBeViewedInKaleidoscope: Bool + let canBeSwapped: Bool let testResult: SnapshotTestResult - init(testResult: SnapshotTestResult, kaleidoscopeViewer: ExternalViewer.Type = KaleidoscopeViewer.self) { + init(testResult: SnapshotTestResult, kaleidoscopeViewer: ExternalViewer.Type = KaleidoscopeViewer.self, swapper: SnapshotTestResultSwapper = SnapshotTestResultSwapper()) { self.testResult = testResult + self.canBeSwapped = swapper.canSwap(testResult) self.canBeViewedInKaleidoscope = kaleidoscopeViewer.isAvailable() && kaleidoscopeViewer.canView(snapshotTestResult: testResult) switch testResult { case let .recorded(_, referenceImagePath, _): @@ -31,7 +33,7 @@ struct TestResultDisplayInfo: AutoEquatable { self.failedImageURL = URL(fileURLWithPath: failedImagePath) } let testNameComponents = testResult.testName.replacingOccurrences(of: "_", with: " ").components(separatedBy: " ") - self.testContext = testNameComponents[0..<(testNameComponents.count - 1)].joined(separator: " ") + self.testContext = testNameComponents.count > 1 ? testResult.testClassName + " " + testNameComponents[0..<(testNameComponents.count - 1)].joined(separator: " ") : testResult.testClassName self.testName = testNameComponents[testNameComponents.count - 1] } } diff --git a/FBSnapshotsViewer/Test Results/Presenter/TestResultsCollectionViewOutlets.swift b/FBSnapshotsViewer/Test Results/Presenter/TestResultsCollectionViewOutlets.swift index 40a697c..5158bff 100644 --- a/FBSnapshotsViewer/Test Results/Presenter/TestResultsCollectionViewOutlets.swift +++ b/FBSnapshotsViewer/Test Results/Presenter/TestResultsCollectionViewOutlets.swift @@ -11,8 +11,9 @@ import AppKit class TestResultsCollectionViewOutlets: NSObject { var testResultsDisplayInfo: TestResultsDisplayInfo = TestResultsDisplayInfo() fileprivate weak var testResultCellDelegate: TestResultCellDelegate? + fileprivate weak var testResultsHeaderDelegate: TestResultsHeaderDelegate? - init(collectionView: NSCollectionView, testResultCellDelegate: TestResultCellDelegate? = nil) { + init(collectionView: NSCollectionView, testResultCellDelegate: TestResultCellDelegate? = nil, testResultsHeaderDelegate: TestResultsHeaderDelegate? = nil) { guard let testResultCellNib = NSNib(nibNamed: TestResultCell.itemIdentifier, bundle: Bundle.main), let testResultHeaderNib = NSNib(nibNamed: TestResultsHeader.itemIdentifier, bundle: Bundle.main) else { fatalError("TestResultCell || TestResultsHeader is missing in bundle") @@ -20,6 +21,7 @@ class TestResultsCollectionViewOutlets: NSObject { collectionView.register(testResultCellNib, forItemWithIdentifier: TestResultCell.itemIdentifier) collectionView.register(testResultHeaderNib, forSupplementaryViewOfKind: NSCollectionElementKindSectionHeader, withIdentifier: TestResultsHeader.itemIdentifier) self.testResultCellDelegate = testResultCellDelegate + self.testResultsHeaderDelegate = testResultsHeaderDelegate super.init() } } @@ -59,8 +61,9 @@ extension TestResultsCollectionViewOutlets: NSCollectionViewDataSource { guard let view = collectionView.makeSupplementaryView(ofKind: NSCollectionElementKindSectionHeader, withIdentifier: TestResultsHeader.itemIdentifier, for: indexPath) as? TestResultsHeader else { fatalError("TestResultsHeader is not registered in collection view") } - let titleInfo = testResultsDisplayInfo.sectionInfos[indexPath.section].titleInfo - view.configure(with: titleInfo) + let sectionInfo = testResultsDisplayInfo.sectionInfos[indexPath.section] + view.configure(with: sectionInfo) + view.delegate = self.testResultsHeaderDelegate return view } diff --git a/FBSnapshotsViewer/Test Results/Presenter/TestResultsDisplayInfosCollector.swift b/FBSnapshotsViewer/Test Results/Presenter/TestResultsDisplayInfosCollector.swift index fc85b97..c38546c 100644 --- a/FBSnapshotsViewer/Test Results/Presenter/TestResultsDisplayInfosCollector.swift +++ b/FBSnapshotsViewer/Test Results/Presenter/TestResultsDisplayInfosCollector.swift @@ -31,12 +31,7 @@ class TestResultsDisplayInfosCollector { return groupedTestResults.map { TestResultsSectionDisplayInfo(title: $0.key, items: $0.value) }.sorted { let timeAgo1 = $0.0.titleInfo.timeAgoDate let timeAgo2 = $0.1.titleInfo.timeAgoDate - if timeAgo1 != timeAgo2 { - return timeAgo1 > timeAgo2 - } - else { - return $0.0.titleInfo.title > $0.1.titleInfo.title - } + return timeAgo1 != timeAgo2 ? timeAgo1 >= timeAgo2 : $0.0.titleInfo.title > $0.1.titleInfo.title } } diff --git a/FBSnapshotsViewer/Test Results/Presenter/TestResultsPresenter.swift b/FBSnapshotsViewer/Test Results/Presenter/TestResultsPresenter.swift index 1042d00..1bf0ec4 100644 --- a/FBSnapshotsViewer/Test Results/Presenter/TestResultsPresenter.swift +++ b/FBSnapshotsViewer/Test Results/Presenter/TestResultsPresenter.swift @@ -37,4 +37,21 @@ extension TestResultsPresenter: TestResultsModuleInterface { selectedDiffMode = diffMode updateUserInterface() } + + func swap(_ testResults: [TestResultDisplayInfo]) { + for testResultInfo in testResults { + interactor?.swap(testResult: testResultInfo.testResult) + } + updateUserInterface() + } +} + +extension TestResultsPresenter: TestResultsInteractorOutput { + func didFailToSwap(testResult: SnapshotTestResult, with error: Error) { + let failToSwapAlert = NSAlert() + failToSwapAlert.addButton(withTitle: "Ok") + failToSwapAlert.alertStyle = .critical + failToSwapAlert.messageText = "Ops, swap can not be done. \(error.localizedDescription). Please report an issue https://github.com/Antondomashnev/FBSnapshotsViewer/issues/new" + failToSwapAlert.runModal() + } } diff --git a/FBSnapshotsViewer/Test Results/Presenter/TestResultsSectionDisplayInfo.swift b/FBSnapshotsViewer/Test Results/Presenter/TestResultsSectionDisplayInfo.swift index 36a0183..d9c78a1 100644 --- a/FBSnapshotsViewer/Test Results/Presenter/TestResultsSectionDisplayInfo.swift +++ b/FBSnapshotsViewer/Test Results/Presenter/TestResultsSectionDisplayInfo.swift @@ -35,6 +35,10 @@ struct TestResultsSectionDisplayInfo: AutoEquatable { let titleInfo: TestResultsSectionTitleDisplayInfo let itemInfos: [TestResultDisplayInfo] + var hasItemsToSwap: Bool { + return itemInfos.index { $0.canBeSwapped } != nil ? true : false + } + init(title: TestResultsSectionTitleDisplayInfo, items: [TestResultDisplayInfo] = []) { self.titleInfo = title self.itemInfos = items diff --git a/FBSnapshotsViewer/Test Results/TestResultsModuleInterface.swift b/FBSnapshotsViewer/Test Results/TestResultsModuleInterface.swift index 5eb231d..1de0032 100644 --- a/FBSnapshotsViewer/Test Results/TestResultsModuleInterface.swift +++ b/FBSnapshotsViewer/Test Results/TestResultsModuleInterface.swift @@ -12,4 +12,5 @@ protocol TestResultsModuleInterface: class, AutoMockable { func updateUserInterface() func openInKaleidoscope(testResultDisplayInfo: TestResultDisplayInfo) func selectDiffMode(_ diffMode: TestResultsDiffMode) + func swap(_ testResults: [TestResultDisplayInfo]) } diff --git a/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.swift b/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.swift index 2322a0d..c03f05e 100644 --- a/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.swift +++ b/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.swift @@ -11,6 +11,7 @@ import Nuke protocol TestResultCellDelegate: class, AutoMockable { func testResultCell(_ cell: TestResultCell, viewInKaleidoscopeButtonClicked: NSButton) + func testResultCell(_ cell: TestResultCell, swapSnapshotsButtonClicked: NSButton) } class TestResultCell: NSCollectionViewItem { @@ -20,6 +21,7 @@ class TestResultCell: NSCollectionViewItem { @IBOutlet private weak var actionsContainerView: NSView! @IBOutlet private weak var viewInKaleidoscopeButton: NSButton! + @IBOutlet private weak var swapSnapshotsButton: NSButton! @IBOutlet private weak var imagesContainerView: NSView! @IBOutlet private weak var failedImageView: NSImageView! @@ -90,6 +92,7 @@ class TestResultCell: NSCollectionViewItem { if let failedImageURL = testResult.failedImageURL { Nuke.loadImage(with: failedImageURL, into: failedImageView) } + swapSnapshotsButton.isHidden = !testResult.canBeSwapped viewInKaleidoscopeButton.isHidden = !testResult.canBeViewedInKaleidoscope testNameLabel.stringValue = testResult.testName } @@ -98,6 +101,7 @@ class TestResultCell: NSCollectionViewItem { referenceImageView.image = nil diffImageView.image = nil failedImageView.image = nil + splitContainerView.resetUI() } // MARK: - Interface @@ -115,4 +119,8 @@ class TestResultCell: NSCollectionViewItem { @objc @IBAction func viewInKaleidoscopeButtonClicked(_ sender: NSButton) { delegate?.testResultCell(self, viewInKaleidoscopeButtonClicked: sender) } + + @objc @IBAction func swapSnapshotsButtonClicked(_ sender: NSButton) { + delegate?.testResultCell(self, swapSnapshotsButtonClicked: sender) + } } diff --git a/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.xib b/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.xib index bdf8a33..dc24d92 100644 --- a/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.xib +++ b/FBSnapshotsViewer/Test Results/User Interface/TestResultCell.xib @@ -1,5 +1,5 @@ - + @@ -180,8 +180,20 @@ + + + @@ -222,6 +234,7 @@ + diff --git a/FBSnapshotsViewer/Test Results/User Interface/TestResultSplitView.swift b/FBSnapshotsViewer/Test Results/User Interface/TestResultSplitView.swift index e11d0b8..5666ad5 100644 --- a/FBSnapshotsViewer/Test Results/User Interface/TestResultSplitView.swift +++ b/FBSnapshotsViewer/Test Results/User Interface/TestResultSplitView.swift @@ -72,6 +72,7 @@ class TestResultSplitView: NSView { // MARK: - Interface func configure(with testResult: TestResultDisplayInfo, appleInterfaceMode: AppleInterfaceMode = AppleInterfaceMode()) { + resetUI() if let referenceImage = NSImage(contentsOf: testResult.referenceImageURL) { splitReferenceImageView.image = referenceImage } @@ -81,6 +82,11 @@ class TestResultSplitView: NSView { configureBordersColorScheme(for: appleInterfaceMode) } + func resetUI() { + splitReferenceImageView.image = nil + splitFailedImageView.image = nil + } + // MARK: - TrackingEvents override func mouseExited(with event: NSEvent) { diff --git a/FBSnapshotsViewer/Test Results/User Interface/TestResultsController.swift b/FBSnapshotsViewer/Test Results/User Interface/TestResultsController.swift index f842fa4..131d3a2 100644 --- a/FBSnapshotsViewer/Test Results/User Interface/TestResultsController.swift +++ b/FBSnapshotsViewer/Test Results/User Interface/TestResultsController.swift @@ -28,7 +28,7 @@ class TestResultsController: NSViewController { // MARK: - Helpers private func setupCollectionView() { - collectionViewOutlets = TestResultsCollectionViewOutlets(collectionView: collectionView, testResultCellDelegate: self) + collectionViewOutlets = TestResultsCollectionViewOutlets(collectionView: collectionView, testResultCellDelegate: self, testResultsHeaderDelegate: self) collectionView.delegate = collectionViewOutlets collectionView.dataSource = collectionViewOutlets } @@ -43,16 +43,53 @@ extension TestResultsController: TestResultsUserInterface { } extension TestResultsController: TestResultCellDelegate { - func testResultCell(_ cell: TestResultCell, viewInKaleidoscopeButtonClicked: NSButton) { + private func findTestResultInfo(for cell: TestResultCell) -> (info: TestResultDisplayInfo, indexPath: IndexPath)? { let sectionInfos = collectionViewOutlets.testResultsDisplayInfo.sectionInfos guard let cellIndexPath = collectionView.indexPath(for: cell), - sectionInfos.count > cellIndexPath.section, - sectionInfos[cellIndexPath.section].itemInfos.count > cellIndexPath.item else { + sectionInfos.count > cellIndexPath.section, + sectionInfos[cellIndexPath.section].itemInfos.count > cellIndexPath.item else { + return nil + } + let testResultInfo = sectionInfos[cellIndexPath.section].itemInfos[cellIndexPath.item] + return (testResultInfo, cellIndexPath) + } + + func testResultCell(_ cell: TestResultCell, viewInKaleidoscopeButtonClicked: NSButton) { + guard let testResultInfo = findTestResultInfo(for: cell) else { assertionFailure("Unexpected TestResultCellDelegate callback about Kaleidoscope button click") return } - let testResultInfo = sectionInfos[cellIndexPath.section].itemInfos[cellIndexPath.item] - eventHandler.openInKaleidoscope(testResultDisplayInfo: testResultInfo) + eventHandler.openInKaleidoscope(testResultDisplayInfo: testResultInfo.info) + } + + func testResultCell(_ cell: TestResultCell, swapSnapshotsButtonClicked: NSButton) { + guard let testResultInfo = findTestResultInfo(for: cell) else { + assertionFailure("Unexpected TestResultCellDelegate callback about swap snapshots button click") + return + } + eventHandler.swap([testResultInfo.info]) + collectionView.reloadSections(IndexSet(integer: testResultInfo.indexPath.section)) + } +} + +extension TestResultsController: TestResultsHeaderDelegate { + private func findTestResultsSectionDisplayInfo(for header: TestResultsHeader) -> (info: TestResultsSectionDisplayInfo, indexPath: IndexPath)? { + let sectionInfos = collectionViewOutlets.testResultsDisplayInfo.sectionInfos + let headerBounds = header.convert(header.frame, to: view) + guard let headerIndexPath = collectionView.indexPathForItem(at: NSPoint(x: headerBounds.midX, y: headerBounds.midY)), + sectionInfos.count > headerIndexPath.section else { + return nil + } + return (sectionInfos[headerIndexPath.section], headerIndexPath) + } + + func testResultsHeader(_ header: TestResultsHeader, swapSnapshotsButtonClicked: NSButton) { + guard let testResultsSectionInfo = findTestResultsSectionDisplayInfo(for: header) else { + assertionFailure("Unexpected TestResultsHeaderDelegate callback about swap snapshots button click") + return + } + eventHandler.swap(testResultsSectionInfo.info.itemInfos) + collectionView.reloadSections(IndexSet(integer: testResultsSectionInfo.indexPath.section)) } } diff --git a/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.swift b/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.swift index 8cd33aa..2da1012 100644 --- a/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.swift +++ b/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.swift @@ -8,11 +8,18 @@ import AppKit +protocol TestResultsHeaderDelegate: class, AutoMockable { + func testResultsHeader(_ header: TestResultsHeader, swapSnapshotsButtonClicked: NSButton) +} + class TestResultsHeader: NSView, NSCollectionViewSectionHeaderView { static let itemIdentifier = "TestResultsHeader" + weak var delegate: TestResultsHeaderDelegate? + @IBOutlet private weak var contextLabel: NSTextField! @IBOutlet private weak var dateLabel: NSTextField! + @IBOutlet private weak var swapSnapshotsButton: NSButton! // MARK: - Helpers @@ -23,9 +30,16 @@ class TestResultsHeader: NSView, NSCollectionViewSectionHeaderView { // MARK: - Interface - func configure(with sectionTitleInfo: TestResultsSectionTitleDisplayInfo, appleInterfaceMode: AppleInterfaceMode = AppleInterfaceMode()) { - contextLabel.stringValue = sectionTitleInfo.title - dateLabel.stringValue = sectionTitleInfo.timeAgo + func configure(with sectionInfo: TestResultsSectionDisplayInfo, appleInterfaceMode: AppleInterfaceMode = AppleInterfaceMode()) { + contextLabel.stringValue = sectionInfo.titleInfo.title + dateLabel.stringValue = sectionInfo.titleInfo.timeAgo + swapSnapshotsButton.isHidden = !sectionInfo.hasItemsToSwap configureTitleLabelsColorScheme(for: appleInterfaceMode) } + + // MARK: - Actions + + @objc @IBAction func swapSnapshotsButtonClicked(_ sender: NSButton) { + delegate?.testResultsHeader(self, swapSnapshotsButtonClicked: sender) + } } diff --git a/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.xib b/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.xib index 13bfe70..a0318d5 100644 --- a/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.xib +++ b/FBSnapshotsViewer/Test Results/User Interface/TestResultsHeader.xib @@ -1,5 +1,5 @@ - + @@ -25,14 +25,26 @@ - + + + + @@ -41,6 +53,7 @@ + diff --git a/FBSnapshotsViewer/Test Results/Wireframe/TestResultsWireframe.swift b/FBSnapshotsViewer/Test Results/Wireframe/TestResultsWireframe.swift index 9aeeca0..0007226 100644 --- a/FBSnapshotsViewer/Test Results/Wireframe/TestResultsWireframe.swift +++ b/FBSnapshotsViewer/Test Results/Wireframe/TestResultsWireframe.swift @@ -12,7 +12,7 @@ final class TestResultsWireframe { func show(relativeTo rect: NSRect, of view: NSView, with testResults: [SnapshotTestResult]) { let userInterface = StoryboardScene.Main.instantiateTestResultsController() - let interactor = TestResultsInteractor(testResults: testResults) + let interactor = TestResultsInteractor(builder: TestResultsInteractorBuilder(clojure: {_ in})) let presenter = TestResultsPresenter() let popover = NSPopover() popover.behavior = .transient diff --git a/FBSnapshotsViewerTests/ApplicationLogLineSpec.swift b/FBSnapshotsViewerTests/ApplicationLogLineSpec.swift index a5a4dce..c0fe48e 100644 --- a/FBSnapshotsViewerTests/ApplicationLogLineSpec.swift +++ b/FBSnapshotsViewerTests/ApplicationLogLineSpec.swift @@ -37,6 +37,14 @@ class ApplicationLogLineSpec: QuickSpec { expect(ApplicationLogLine(line: line)).to(equal(ApplicationLogLine.applicationNameMessage(line: line))) } } + + context("when line with FB_REFERENCE_IMAGE_DIR environment variable") { + let line = "\"FB_REFERENCE_IMAGE_DIR\" = \"/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages\";" + + it("returns fbReferenceImageDirMessage log line") { + expect(ApplicationLogLine(line: line)).to(equal(ApplicationLogLine.fbReferenceImageDirMessage(line: line))) + } + } context("when random line") { let line = "21:15:27.395 Xcode[4221:116855] Beginning test session FBSnapshotsViewerExampleTests-C6CA3D7B-D217-41C0-8B95-2E9C49ECA4C2 at 2017-04-25 21:15:27.395 with Xcode 8E2002 on target {" diff --git a/FBSnapshotsViewerTests/ApplicationLogReaderSpec.swift b/FBSnapshotsViewerTests/ApplicationLogReaderSpec.swift index af65c13..9f7d52f 100644 --- a/FBSnapshotsViewerTests/ApplicationLogReaderSpec.swift +++ b/FBSnapshotsViewerTests/ApplicationLogReaderSpec.swift @@ -29,6 +29,7 @@ class ApplicationLogReaderrSpec: QuickSpec { logLines = reader.readline(of: log, startingFrom: 0) expect(logLines.count).to(equal(31)) expect(logLines[4]).to(equal(ApplicationLogLine.applicationNameMessage(line: " "))) + expect(logLines[6]).to(equal(ApplicationLogLine.fbReferenceImageDirMessage(line: " "))) expect(logLines[16]).to(equal(ApplicationLogLine.kaleidoscopeCommandMessage(line: "ksdiff \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/463165DA-5244-400A-87F1-6B5A16441AD7/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png\" \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/463165DA-5244-400A-87F1-6B5A16441AD7/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png\""))) expect(logLines[23]).to(equal(ApplicationLogLine.referenceImageSavedMessage(line: " 2017-06-07 22:45:56.604 FBSnapshotsViewerExample[32663:2211488] Reference image save at: /Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png"))) } @@ -60,6 +61,7 @@ class ApplicationLogReaderrSpec: QuickSpec { it("reads the whole file") { logLines = reader.readline(of: log, startingFrom: 0) expect(logLines.count).to(equal(288)) + expect(logLines[49]).to(equal(ApplicationLogLine.fbReferenceImageDirMessage(line: "\"FB_REFERENCE_IMAGE_DIR\" = \"/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages\";"))) expect(logLines[52]).to(equal(ApplicationLogLine.applicationNameMessage(line: "XCInjectBundleInto = \"/Users/antondomashnev/Library/Developer/Xcode/DerivedData/FBSnapshotsViewerExample-eeuapqepwoebslcfqojhfzyfuhmp/Build/Products/Debug-iphonesimulator/FBSnapshotsViewerExample.app/FBSnapshotsViewerExample\";"))) expect(logLines[247]).to(equal(ApplicationLogLine.kaleidoscopeCommandMessage(line: "ksdiff \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png\" \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png\""))) expect(logLines[260]).to(equal(ApplicationLogLine.referenceImageSavedMessage(line: "2017-04-25 21:15:37.107 FBSnapshotsViewerExample[56034:787919] Reference image save at: /Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png"))) diff --git a/FBSnapshotsViewerTests/ApplicationNameExtractorSpec.swift b/FBSnapshotsViewerTests/ApplicationNameExtractorSpec.swift index 51eda8a..314c53f 100644 --- a/FBSnapshotsViewerTests/ApplicationNameExtractorSpec.swift +++ b/FBSnapshotsViewerTests/ApplicationNameExtractorSpec.swift @@ -25,6 +25,8 @@ class XcodeApplicationNameExtractorSpec: QuickSpec { expect { try extractor.extractApplicationName(from: ApplicationLogLine.kaleidoscopeCommandMessage(line: "ksdiff \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png\" \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png\"")) }.to(throwError()) expect { try extractor.extractApplicationName(from: ApplicationLogLine.kaleidoscopeCommandMessage(line: "2017-04-25 21:15:37.107 FBSnapshotsViewerExample[56034:787919] Reference image save at: /Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png")) }.to(throwError()) + + expect { try extractor.extractApplicationName(from: ApplicationLogLine.fbReferenceImageDirMessage(line: "\"FB_REFERENCE_IMAGE_DIR\" = \"/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages\";")) }.to(throwError()) expect { try extractor.extractApplicationName(from: ApplicationLogLine.unknown) }.to(throwError()) } @@ -62,7 +64,9 @@ class AppCodeApplicationNameExtractorSpec: QuickSpec { expect { try extractor.extractApplicationName(from: ApplicationLogLine.kaleidoscopeCommandMessage(line: "ksdiff \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png\" \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png\"")) }.to(throwError()) expect { try extractor.extractApplicationName(from: ApplicationLogLine.kaleidoscopeCommandMessage(line: "2017-04-25 21:15:37.107 FBSnapshotsViewerExample[56034:787919] Reference image save at: /Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png")) }.to(throwError()) - + + expect { try extractor.extractApplicationName(from: ApplicationLogLine.fbReferenceImageDirMessage(line: " ")) }.to(throwError()) + expect { try extractor.extractApplicationName(from: ApplicationLogLine.unknown) }.to(throwError()) } } diff --git a/FBSnapshotsViewerTests/ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift b/FBSnapshotsViewerTests/ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift new file mode 100644 index 0000000..e960894 --- /dev/null +++ b/FBSnapshotsViewerTests/ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift @@ -0,0 +1,180 @@ +// +// ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec.swift +// FBSnapshotsViewerTests +// +// Created by Anton Domashnev on 24.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Quick +import Nimble + +@testable import FBSnapshotsViewer + +class ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockApplicationLogReader: ApplicationLogReader { + var readLines: [ApplicationLogLine] = [] + override func readline(of logText: String, startingFrom lineNumber: Int) -> [ApplicationLogLine] { + return readLines + } +} + +class ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockSnapshotTestResultFactory: SnapshotTestResultFactory { + var createdSnapshotTestResultForLogLine: [ApplicationLogLine: SnapshotTestResult] = [:] + var givenBuild: Build! + override func createSnapshotTestResult(from logLine: ApplicationLogLine, build: Build) -> SnapshotTestResult? { + givenBuild = build + return createdSnapshotTestResultForLogLine[logLine] + } +} + +class ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockApplicationNameExtractor: ApplicationNameExtractor { + var extractApplicationNameCalled = false + var extractApplicationNameThrows = false + var extractApplicationNameReceivedLogLine: ApplicationLogLine? + var extractApplicationNameReturnValue: String! + + func extractApplicationName(from logLine: ApplicationLogLine) throws -> String { + if extractApplicationNameThrows { + throw NSError(domain: "", code: 0, userInfo: nil) + } + extractApplicationNameCalled = true + extractApplicationNameReceivedLogLine = logLine + return extractApplicationNameReturnValue + } +} + +class ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockBuildCreator: BuildCreator { + var createdBuild: Build? + + override func createBuild() -> Build? { + return createdBuild + } +} + +class ApplicationSnapshotTestResultFileWatcherUpdateHandler__MockFBReferenceImageDirectoryURLExtractor: FBReferenceImageDirectoryURLExtractor { + var extractImageDirectoryURLCalled = false + var extractImageDirectoryURLThrows = false + var extractImageDirectoryURLReceivedLogLine: ApplicationLogLine? + var extractImageDirectoryURLReturnValue: URL! + + func extractImageDirectoryURL(from logLine: ApplicationLogLine) throws -> URL { + if extractImageDirectoryURLThrows { + throw NSError(domain: "", code: 0, userInfo: nil) + } + extractImageDirectoryURLCalled = true + extractImageDirectoryURLReceivedLogLine = logLine + return extractImageDirectoryURLReturnValue + } +} + +class ApplicationSnapshotTestResultFileWatcherUpdateHandlerSpec: QuickSpec { + override func spec() { + var logReader: ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockApplicationLogReader! + var snapshotTestResultFactory: ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockSnapshotTestResultFactory! + var applicationNameExtractor: ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockApplicationNameExtractor! + var buildCreator: ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockBuildCreator! + var fbImageReferenceDirExtractor: ApplicationSnapshotTestResultFileWatcherUpdateHandler__MockFBReferenceImageDirectoryURLExtractor! + var updateHandler: ApplicationSnapshotTestResultFileWatcherUpdateHandler! + + beforeEach { + logReader = ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockApplicationLogReader() + applicationNameExtractor = ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockApplicationNameExtractor() + snapshotTestResultFactory = ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockSnapshotTestResultFactory() + buildCreator = ApplicationSnapshotTestResultFileWatcherUpdateHandler_MockBuildCreator() + fbImageReferenceDirExtractor = ApplicationSnapshotTestResultFileWatcherUpdateHandler__MockFBReferenceImageDirectoryURLExtractor() + let builder = ApplicationSnapshotTestResultFileWatcherUpdateHandlerBuilder { + $0.applicationNameExtractor = applicationNameExtractor + $0.fbImageReferenceDirExtractor = fbImageReferenceDirExtractor + $0.snapshotTestResultFactory = snapshotTestResultFactory + $0.buildCreator = buildCreator + $0.applicationLogReader = logReader + } + updateHandler = ApplicationSnapshotTestResultFileWatcherUpdateHandler(builder: builder) + } + + describe(".handleFileWatcherUpdate") { + let build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let unknownLogLine = ApplicationLogLine.unknown + let applicationNameMessageLogLine = ApplicationLogLine.applicationNameMessage(line: "MyApp") + let kaleidoscopeCommandMesageLogLine = ApplicationLogLine.kaleidoscopeCommandMessage(line: "BlaBla") + let referenceImageSavedMessageLogLine = ApplicationLogLine.referenceImageSavedMessage(line: "FooFoo") + let fbReferenceImageDirMessageLogLine = ApplicationLogLine.fbReferenceImageDirMessage(line: "foo/bar") + let failedSnapshotTestResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "Foo", testName: "failedTest"), referenceImagePath: "referenceTestImage.png", diffImagePath: "diffTestImage.png", failedImagePath: "failedTestImage.png", build: build) + let recordedSnapshotTestResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "recordedTest"), referenceImagePath: "referenceTestImage.png", build: build) + + beforeEach { + applicationNameExtractor.extractApplicationNameReturnValue = "MyApp" + fbImageReferenceDirExtractor.extractImageDirectoryURLReturnValue = URL(fileURLWithPath: "foo/bar", isDirectory: true) + snapshotTestResultFactory.createdSnapshotTestResultForLogLine[kaleidoscopeCommandMesageLogLine] = failedSnapshotTestResult + snapshotTestResultFactory.createdSnapshotTestResultForLogLine[referenceImageSavedMessageLogLine] = recordedSnapshotTestResult + logReader.readLines = [unknownLogLine, fbReferenceImageDirMessageLogLine, applicationNameMessageLogLine, kaleidoscopeCommandMesageLogLine, referenceImageSavedMessageLogLine] + } + + context("with no changes") { + it("outputs empty array") { + expect(updateHandler.handleFileWatcherUpdate(result: .noChanges)).to(equal([])) + } + } + + context("with invalid updates") { + it("thows assertion") { + expect { updateHandler.handleFileWatcherUpdate(result: .updated(data: Data())) }.to(throwAssertion()) + } + } + + context("with valid updates") { + let update: Data! = "new updated text".data(using: .utf8, allowLossyConversion: false) + + it("assigns values to buildCreator") { + buildCreator.createdBuild = build + + updateHandler.handleFileWatcherUpdate(result: .updated(data: update)) + + expect(buildCreator.date).toNot(beNil()) + expect(buildCreator.applicationName).to(equal(applicationNameExtractor.extractApplicationNameReturnValue)) + expect(buildCreator.fbReferenceImageDirectoryURL).to(equal(fbImageReferenceDirExtractor.extractImageDirectoryURLReturnValue)) + } + + context("when build can not be created") { + beforeEach { + buildCreator.createdBuild = nil + } + + it("throws assertion") { + expect { updateHandler.handleFileWatcherUpdate(result: .updated(data: update)) }.to(throwAssertion()) + } + } + + context("when fb reference image dir can not be extracted") { + beforeEach { + fbImageReferenceDirExtractor.extractImageDirectoryURLThrows = true + } + + it("throws assertion") { + expect { updateHandler.handleFileWatcherUpdate(result: .updated(data: update)) }.to(throwAssertion()) + } + } + + context("when application name can not be extracted") { + beforeEach { + applicationNameExtractor.extractApplicationNameThrows = true + } + + it("throws assertion") { + expect { updateHandler.handleFileWatcherUpdate(result: .updated(data: update)) }.to(throwAssertion()) + } + } + + context("when build can be constructed") { + beforeEach { + buildCreator.createdBuild = build + } + + it("returns test results") { + expect(updateHandler.handleFileWatcherUpdate(result: .updated(data: update))).to(equal([failedSnapshotTestResult, recordedSnapshotTestResult])) + } + } + } + } + } +} diff --git a/FBSnapshotsViewerTests/ApplicationSnapshotTestResultListenerSpec.swift b/FBSnapshotsViewerTests/ApplicationSnapshotTestResultListenerSpec.swift index f82b192..b2c74ce 100644 --- a/FBSnapshotsViewerTests/ApplicationSnapshotTestResultListenerSpec.swift +++ b/FBSnapshotsViewerTests/ApplicationSnapshotTestResultListenerSpec.swift @@ -30,52 +30,24 @@ class ApplicationSnapshotTestResultListener_MockFileWatcherProtocol: KZFileWatch } } -class ApplicationSnapshotTestResultListener_MockApplicationLogReader: ApplicationLogReader { - var readLines: [ApplicationLogLine] = [] - override func readline(of logText: String, startingFrom lineNumber: Int) -> [ApplicationLogLine] { - return readLines - } -} - -class ApplicationSnapshotTestResultListener_MockSnapshotTestResultFactory: SnapshotTestResultFactory { - var createdSnapshotTestResultForLogLine: [ApplicationLogLine: SnapshotTestResult] = [:] - var givenBuild: Build! - override func createSnapshotTestResult(from logLine: ApplicationLogLine, build: Build) -> SnapshotTestResult? { - givenBuild = build - return createdSnapshotTestResultForLogLine[logLine] - } -} - -class ApplicationSnapshotTestResultListener_MockApplicationNameExtractor: ApplicationNameExtractor { - var extractApplicationNameCalled = false - var extractApplicationNameThrows = false - var extractApplicationNameReceivedLogLine: ApplicationLogLine? - var extractApplicationNameReturnValue: String! +class ApplicationSnapshotTestResultListener_MockApplicationSnapshotTestResultFileWatcherUpdateHandler: ApplicationSnapshotTestResultFileWatcherUpdateHandler { + var createdTestResults: [SnapshotTestResult] = [] - func extractApplicationName(from logLine: ApplicationLogLine) throws -> String { - if extractApplicationNameThrows { - throw NSError(domain: "", code: 0, userInfo: nil) - } - extractApplicationNameCalled = true - extractApplicationNameReceivedLogLine = logLine - return extractApplicationNameReturnValue + override func handleFileWatcherUpdate(result: KZFileWatchers.FileWatcher.RefreshResult) -> [SnapshotTestResult] { + return createdTestResults } } class ApplicationSnapshotTestResultListenerSpec: QuickSpec { override func spec() { + var updatesHandler: ApplicationSnapshotTestResultListener_MockApplicationSnapshotTestResultFileWatcherUpdateHandler! var fileWatcher: ApplicationSnapshotTestResultListener_MockFileWatcherProtocol! - var logReader: ApplicationSnapshotTestResultListener_MockApplicationLogReader! - var snapshotTestResultFactory: ApplicationSnapshotTestResultListener_MockSnapshotTestResultFactory! - var applicationNameExtractor: ApplicationSnapshotTestResultListener_MockApplicationNameExtractor! var listener: ApplicationSnapshotTestResultListener! beforeEach { - applicationNameExtractor = ApplicationSnapshotTestResultListener_MockApplicationNameExtractor() - snapshotTestResultFactory = ApplicationSnapshotTestResultListener_MockSnapshotTestResultFactory() + updatesHandler = ApplicationSnapshotTestResultListener_MockApplicationSnapshotTestResultFileWatcherUpdateHandler() fileWatcher = ApplicationSnapshotTestResultListener_MockFileWatcherProtocol() - logReader = ApplicationSnapshotTestResultListener_MockApplicationLogReader() - listener = ApplicationSnapshotTestResultListener(fileWatcher: fileWatcher, applicationLogReader: logReader, applicationNameExtractor: applicationNameExtractor, snapshotTestResultFactory: snapshotTestResultFactory) + listener = ApplicationSnapshotTestResultListener(fileWatcher: fileWatcher, fileWatcherUpdateHandler: updatesHandler) } describe(".stopListening") { @@ -86,82 +58,40 @@ class ApplicationSnapshotTestResultListenerSpec: QuickSpec { } describe(".receiving new file watch event") { + let update: Data! = "new updated text".data(using: .utf8, allowLossyConversion: false) var receivedSnapshotTestResults: [SnapshotTestResult] = [] - let build = Build(date: Date(), applicationName: "MyApp") - let unknownLogLine = ApplicationLogLine.unknown - let applicationNameMessageLogLine = ApplicationLogLine.applicationNameMessage(line: "MyApp") - let kaleidoscopeCommandMesageLogLine = ApplicationLogLine.kaleidoscopeCommandMessage(line: "BlaBla") - let referenceImageSavedMessageLogLine = ApplicationLogLine.referenceImageSavedMessage(line: "FooFoo") - let failedSnapshotTestResult = SnapshotTestResult.failed(testName: "failedTest", referenceImagePath: "referenceTestImage.png", diffImagePath: "diffTestImage.png", failedImagePath: "failedTestImage.png", build: build) - let recordedSnapshotTestResult = SnapshotTestResult.recorded(testName: "recordedTest", referenceImagePath: "referenceTestImage.png", build: build) - + beforeEach { - applicationNameExtractor.extractApplicationNameReturnValue = "MyApp" - snapshotTestResultFactory.createdSnapshotTestResultForLogLine[kaleidoscopeCommandMesageLogLine] = failedSnapshotTestResult - snapshotTestResultFactory.createdSnapshotTestResultForLogLine[referenceImageSavedMessageLogLine] = recordedSnapshotTestResult listener.startListening { result in receivedSnapshotTestResults += [result] } } - context("with no changes") { + context("when updates handler returns empty array") { beforeEach { - fileWatcher.startClosure?(.noChanges) - } - - it("doesnt output anything") { - expect(receivedSnapshotTestResults.isEmpty).to(beTrue()) + updatesHandler.createdTestResults = [] + fileWatcher.startClosure?(.updated(data: update)) } - } - - context("with invalid updates") { - it("thows assertion") { - expect { fileWatcher.startClosure?(.updated(data: Data())) }.to(throwAssertion()) + + it("doesn't call listening callback") { + expect(receivedSnapshotTestResults).to(equal([])) } } - context("with valid updates") { - let update: Data! = "new updated text".data(using: .utf8, allowLossyConversion: false) + context("when updates handler returns some results") { + var build: Build! - context("when application name is unknown at the moment of reading snapshot test result log line") { - beforeEach { - logReader.readLines = [unknownLogLine, kaleidoscopeCommandMesageLogLine, applicationNameMessageLogLine, referenceImageSavedMessageLogLine] - } - - it("thows assertion") { - expect { fileWatcher.startClosure?(.updated(data: update)) }.to(throwAssertion()) - } + beforeEach { + build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) } - context("when application name is known at the moment of reading snapshot test result log line") { - beforeEach { - logReader.readLines = [applicationNameMessageLogLine, kaleidoscopeCommandMesageLogLine, unknownLogLine, referenceImageSavedMessageLogLine] - } - - context("when can not parse application name") { - beforeEach { - applicationNameExtractor.extractApplicationNameThrows = true - } - - it("outputs expected snapshot test resilts") { - expect { fileWatcher.startClosure?(.updated(data: update)) }.to(throwAssertion()) - } - } - - context("when can parse applicaion name") { - beforeEach { - fileWatcher.startClosure?(.updated(data: update)) - } - - it("outputs expected snapshot test resilts") { - expect(receivedSnapshotTestResults).to(equal([failedSnapshotTestResult, recordedSnapshotTestResult])) - } - - it("creates test results with correct build") { - expect(snapshotTestResultFactory.givenBuild.applicationName) == applicationNameExtractor.extractApplicationNameReturnValue - expect(snapshotTestResultFactory.givenBuild.date.timeIntervalSince1970).to(beCloseTo(Date().timeIntervalSince1970, within: 0.01)) - } - } + beforeEach { + updatesHandler.createdTestResults = [SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "Foo"), referenceImagePath: "path", build: build)] + fileWatcher.startClosure?(.updated(data: update)) + } + + it("calls listening callback") { + expect(receivedSnapshotTestResults).to(equal(updatesHandler.createdTestResults)) } } } diff --git a/FBSnapshotsViewerTests/ApplicationTestLogFilesListenerSpec.swift b/FBSnapshotsViewerTests/ApplicationTestLogFilesListenerSpec.swift index fc7c3d7..8a0c5b4 100644 --- a/FBSnapshotsViewerTests/ApplicationTestLogFilesListenerSpec.swift +++ b/FBSnapshotsViewerTests/ApplicationTestLogFilesListenerSpec.swift @@ -91,7 +91,7 @@ class ApplicationTestLogFilesListenerSpec: QuickSpec { } it("stops current listening") { - expect(applicationTestLogsEventsListener.stopListeningCalled).to(beTrue()) + expect(applicationTestLogsEventsListener.stopListening_Called).to(beTrue()) } } @@ -100,7 +100,7 @@ class ApplicationTestLogFilesListenerSpec: QuickSpec { } it("starts listening") { - expect(applicationTestLogsEventsListener.startListeningCalled).to(beTrue()) + expect(applicationTestLogsEventsListener.startListening_Called).to(beTrue()) } } } diff --git a/FBSnapshotsViewerTests/BuildCreatorSpec.swift b/FBSnapshotsViewerTests/BuildCreatorSpec.swift new file mode 100644 index 0000000..1fa7c84 --- /dev/null +++ b/FBSnapshotsViewerTests/BuildCreatorSpec.swift @@ -0,0 +1,60 @@ +// +// BuildCreatorSpec.swift +// FBSnapshotsViewerTests +// +// Created by Anton Domashnev on 24.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Quick +import Nimble + +@testable import FBSnapshotsViewer + +class BuildCreatorSpec: QuickSpec { + override func spec() { + var buildCreator: BuildCreator! + + beforeEach { + buildCreator = BuildCreator() + } + + describe(".createBuild") { + context("given application name, date and fbReferenceImageDirectoryURL") { + var date: Date! + var applicationName: String! + var fbReferenceImageDirectoryURL: URL! + + beforeEach { + fbReferenceImageDirectoryURL = URL(fileURLWithPath: "/Users/fedotiy/myproject/tests/") + applicationName = "MyApplication" + date = Date() + buildCreator.applicationName = applicationName + buildCreator.fbReferenceImageDirectoryURL = fbReferenceImageDirectoryURL + buildCreator.date = date + } + + it("returns build") { + let expectedBuild = Build(date: date, applicationName: applicationName, fbReferenceImageDirectoryURL: fbReferenceImageDirectoryURL) + expect(buildCreator.createBuild()).to(equal(expectedBuild)) + } + } + + context("given not all properties") { + var date: Date! + var fbReferenceImageDirectoryURL: URL! + + beforeEach { + fbReferenceImageDirectoryURL = URL(fileURLWithPath: "/Users/fedotiy/myproject/tests/") + date = Date() + buildCreator.fbReferenceImageDirectoryURL = fbReferenceImageDirectoryURL + buildCreator.date = date + } + + it("doesn't create build") { + expect(buildCreator.createBuild()).to(beNil()) + } + } + } + } +} diff --git a/FBSnapshotsViewerTests/FBReferenceImageDirectoryURLExtractorSpec.swift b/FBSnapshotsViewerTests/FBReferenceImageDirectoryURLExtractorSpec.swift new file mode 100644 index 0000000..792d8ce --- /dev/null +++ b/FBSnapshotsViewerTests/FBReferenceImageDirectoryURLExtractorSpec.swift @@ -0,0 +1,92 @@ +// +// FBReferenceImageDirectoryURLExtractorSpec.swift +// FBSnapshotsViewerTests +// +// Created by Anton Domashnev on 24.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Quick +import Nimble + +@testable import FBSnapshotsViewer + +class XcodeFBReferenceImageDirectoryURLExtractorSpec: QuickSpec { + override func spec() { + var extractor: XcodeFBReferenceImageDirectoryURLExtractor! + + beforeEach { + extractor = XcodeFBReferenceImageDirectoryURLExtractor() + } + + describe(".extractImageDirectoryURL") { + context("when unexpected log line is given") { + it("throws an error") { + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.kaleidoscopeCommandMessage(line: "ksdiff \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png\" \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png\"")) }.to(throwError()) + + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.referenceImageSavedMessage(line: "2017-04-25 21:15:37.107 FBSnapshotsViewerExample[56034:787919] Reference image save at: /Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png")) }.to(throwError()) + + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.applicationNameMessage(line: "XCInjectBundleInto = \"/Users/antondomashnev/Library/Developer/Xcode/DerivedData/FBSnapshotsViewerExample-eeuapqepwoebslcfqojhfzyfuhmp/Build/Products/Debug-iphonesimulator/FBSnapshotsViewerExample.app/FBSnapshotsViewerExample\";")) }.to(throwError()) + + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.unknown) }.to(throwError()) + } + } + + context("when fbReferenceImageDirMessage log line given") { + context("with unexpected format") { + it("throws an error") { + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.fbReferenceImageDirMessage(line: "XCInjectBundleInto = ")) }.to(throwError()) + } + } + + context("with expected format") { + it("extracts correct application name") { + let applicationName = try? extractor.extractImageDirectoryURL(from: ApplicationLogLine.fbReferenceImageDirMessage(line: "\"FB_REFERENCE_IMAGE_DIR\" = \"/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages\";")) + let expectedURL = URL(fileURLWithPath: "/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64", isDirectory: true) + expect(applicationName).to(equal(expectedURL)) + } + } + } + } + } +} + +class AppCodeFBReferenceImageDirectoryURLExtractorSpec: QuickSpec { + override func spec() { + var extractor: AppCodeFBReferenceImageDirectoryURLExtractor! + + beforeEach { + extractor = AppCodeFBReferenceImageDirectoryURLExtractor() + } + + describe(".extractImageDirectoryURL") { + context("when unexpected log line is given") { + it("throws an error") { + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.kaleidoscopeCommandMessage(line: "ksdiff \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png\" \"/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png\"")) }.to(throwError()) + + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.kaleidoscopeCommandMessage(line: "2017-04-25 21:15:37.107 FBSnapshotsViewerExample[56034:787919] Reference image save at: /Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png")) }.to(throwError()) + + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.applicationNameMessage(line: "")) }.to(throwError()) + + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.unknown) }.to(throwError()) + } + } + + context("when fbReferenceImageDirMessage log line given") { + context("with unexpected format") { + it("throws an error") { + expect { try extractor.extractImageDirectoryURL(from: ApplicationLogLine.fbReferenceImageDirMessage(line: "XCInjectBundleInto = ")) }.to(throwError()) + } + } + + context("with expected format") { + it("extracts correct application name") { + let applicationName = try? extractor.extractImageDirectoryURL(from: ApplicationLogLine.fbReferenceImageDirMessage(line: " ")) + let expectedURL = URL(fileURLWithPath: "/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64", isDirectory: true) + expect(applicationName).to(equal(expectedURL)) + } + } + } + } + } +} diff --git a/FBSnapshotsViewerTests/KaleidoscopeViewerSpec.swift b/FBSnapshotsViewerTests/KaleidoscopeViewerSpec.swift index c29486a..bd53dac 100644 --- a/FBSnapshotsViewerTests/KaleidoscopeViewerSpec.swift +++ b/FBSnapshotsViewerTests/KaleidoscopeViewerSpec.swift @@ -59,8 +59,8 @@ class KaleidoscopeViewerSpec: QuickSpec { context("for recorded snapshot test result") { beforeEach { - build = Build(applicationName: "MyApp") - testResult = SnapshotTestResult.recorded(testName: "testName", referenceImagePath: "foo/bar/referenceImage.png", build: build) + build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + testResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "ExampleTestClass", testName: "testName"), referenceImagePath: "foo/bar/referenceImage.png", build: build) } it("returns false") { @@ -70,8 +70,8 @@ class KaleidoscopeViewerSpec: QuickSpec { context("for failed snapshot test result") { beforeEach { - build = Build(applicationName: "MyApp") - testResult = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "foo/bar/referenceImage.png", diffImagePath: "foo/bar/diffImage.png", failedImagePath: "foo/bar/failedImage.png", build: build) + build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "ExampleTestClass", testName: "testName"), referenceImagePath: "foo/bar/referenceImage.png", diffImagePath: "foo/bar/diffImage.png", failedImagePath: "foo/bar/failedImage.png", build: build) } it("returns true") { @@ -108,8 +108,8 @@ class KaleidoscopeViewerSpec: QuickSpec { context("for recorded snapshot test result") { beforeEach { - build = Build(date: Date(), applicationName: "MyApp") - testResult = SnapshotTestResult.recorded(testName: "testName", referenceImagePath: "foo/bar/referenceImage.png", build: build) + build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + testResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "ExampleTestClass", testName: "testName"), referenceImagePath: "foo/bar/referenceImage.png", build: build) } it("throws an assertion") { @@ -119,8 +119,8 @@ class KaleidoscopeViewerSpec: QuickSpec { context("for failed snapshot test result") { beforeEach { - build = Build(date: Date(), applicationName: "MyApp") - testResult = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "foo/bar/referenceImage.png", diffImagePath: "foo/bar/diffImage.png", failedImagePath: "foo/bar/failedImage.png", build: build) + build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "ExampleTestClass", testName: "testName"), referenceImagePath: "foo/bar/referenceImage.png", diffImagePath: "foo/bar/diffImage.png", failedImagePath: "foo/bar/failedImage.png", build: build) } it("launches correct process") { diff --git a/FBSnapshotsViewerTests/MenuControllerSpec.swift b/FBSnapshotsViewerTests/MenuControllerSpec.swift index 6c01c30..4a69710 100644 --- a/FBSnapshotsViewerTests/MenuControllerSpec.swift +++ b/FBSnapshotsViewerTests/MenuControllerSpec.swift @@ -83,7 +83,7 @@ class MenuControllerSpec: QuickSpec { } it("quits") { - expect(eventHandler.quitCalled).to(beTrue()) + expect(eventHandler.quit_Called).to(beTrue()) } } @@ -93,7 +93,7 @@ class MenuControllerSpec: QuickSpec { } it("quits") { - expect(eventHandler.showPreferencesCalled).to(beTrue()) + expect(eventHandler.showPreferences_Called).to(beTrue()) } } @@ -103,7 +103,7 @@ class MenuControllerSpec: QuickSpec { } it("quits") { - expect(eventHandler.checkForUpdatesCalled).to(beTrue()) + expect(eventHandler.checkForUpdates_Called).to(beTrue()) } } @@ -116,7 +116,7 @@ class MenuControllerSpec: QuickSpec { } it("shows application menu") { - expect(eventHandler.showApplicationMenuCalled).to(beTrue()) + expect(eventHandler.showApplicationMenu_Called).to(beTrue()) } } @@ -128,7 +128,7 @@ class MenuControllerSpec: QuickSpec { } it("shows test results") { - expect(eventHandler.showTestResultsCalled).to(beTrue()) + expect(eventHandler.showTestResults_Called).to(beTrue()) } } } diff --git a/FBSnapshotsViewerTests/MenuInteractorSpec.swift b/FBSnapshotsViewerTests/MenuInteractorSpec.swift index 687f29f..fe71f3b 100644 --- a/FBSnapshotsViewerTests/MenuInteractorSpec.swift +++ b/FBSnapshotsViewerTests/MenuInteractorSpec.swift @@ -51,13 +51,13 @@ class MenuInteractorSpec: QuickSpec { override func spec() { let testResultsDate = Date() let applicationName = "FBSnapshotsViewer" - let build = Build(date: testResultsDate, applicationName: applicationName) - let testResult1 = SnapshotTestResult.failed(testName: "testName1", referenceImagePath: "referenceImagePath1", diffImagePath: "diffImagePath1", failedImagePath: "failedImagePath1", build: build) - let testResult2 = SnapshotTestResult.failed(testName: "testName2", referenceImagePath: "referenceImagePath2", diffImagePath: "diffImagePath2", failedImagePath: "failedImagePath2", build: build) - let testResult3 = SnapshotTestResult.recorded(testName: "testName3", referenceImagePath: "referenceImagePath3", build: build) + let fbReferenceImageDirURL = URL(fileURLWithPath: "foo/bar", isDirectory: true) + let build = Build(date: testResultsDate, applicationName: applicationName, fbReferenceImageDirectoryURL: fbReferenceImageDirURL) + let testResult1 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClass1", testName: "testName1"), referenceImagePath: "referenceImagePath1", diffImagePath: "diffImagePath1", failedImagePath: "failedImagePath1", build: build) + let testResult2 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClass2", testName: "testName2"), referenceImagePath: "referenceImagePath2", diffImagePath: "diffImagePath2", failedImagePath: "failedImagePath2", build: build) + let testResult3 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "testClass3", testName: "testName3"), referenceImagePath: "referenceImagePath3", build: build) var configuration: FBSnapshotsViewer.Configuration! - var applicationNameExtractor: ApplicationNameExtractorMock! var output: MenuInteractorOutputMock! var interactor: MenuInteractor! var applicationSnapshotTestResultListener: MenuInteractor_MockApplicationSnapshotTestResultListener! @@ -66,9 +66,8 @@ class MenuInteractorSpec: QuickSpec { beforeEach { configuration = Configuration(derivedDataFolder: DerivedDataFolder.xcodeDefault) - applicationNameExtractor = ApplicationNameExtractorMock() output = MenuInteractorOutputMock() - applicationSnapshotTestResultListener = MenuInteractor_MockApplicationSnapshotTestResultListener(fileWatcher: KZFileWatchers.FileWatcher.Local(path: "testpath"), applicationLogReader: ApplicationLogReader(), applicationNameExtractor: applicationNameExtractor) + applicationSnapshotTestResultListener = MenuInteractor_MockApplicationSnapshotTestResultListener(fileWatcher: KZFileWatchers.FileWatcher.Local(path: "testpath"), fileWatcherUpdateHandler: ApplicationSnapshotTestResultFileWatcherUpdateHandler()) applicationSnapshotTestResultListenerFactory = MenuInteractor_MockApplicationSnapshotTestResultListenerFactory() applicationSnapshotTestResultListenerFactory.mockApplicationSnapshotTestResultListener = applicationSnapshotTestResultListener applicationTestLogFilesListener = MenuInteractor_MockApplicationTestLogFilesListener() @@ -96,8 +95,8 @@ class MenuInteractorSpec: QuickSpec { } it("outputs it") { - expect(output.didFindNewTestLogFileCalled).to(beTrue()) - expect(output.didFindNewTestLogFileReceivedPath).to(equal("/Users/antondomashnev/Library/Bla/Bla.log")) + expect(output.didFindNewTestLogFile_at_Called).to(beTrue()) + expect(output.didFindNewTestLogFile_at_ReceivedPath).to(equal("/Users/antondomashnev/Library/Bla/Bla.log")) } } } @@ -122,9 +121,9 @@ class MenuInteractorSpec: QuickSpec { } it("outputs it") { - let build = Build(date: testResultsDate, applicationName: applicationName) - let expectedTestResult = SnapshotTestResult.failed(testName: "testName1", referenceImagePath: "referenceImagePath1", diffImagePath: "diffImagePath1", failedImagePath: "failedImagePath1", build: build) - expect(output.didFindNewTestResultReceivedTestResult).to(equal(expectedTestResult)) + let build = Build(date: testResultsDate, applicationName: applicationName, fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let expectedTestResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClass1", testName: "testName1"), referenceImagePath: "referenceImagePath1", diffImagePath: "diffImagePath1", failedImagePath: "failedImagePath1", build: build) + expect(output.didFindNewTestResult___ReceivedTestResult).to(equal(expectedTestResult)) } } diff --git a/FBSnapshotsViewerTests/MenuPresenterSpec.swift b/FBSnapshotsViewerTests/MenuPresenterSpec.swift index 07499d3..254ceab 100644 --- a/FBSnapshotsViewerTests/MenuPresenterSpec.swift +++ b/FBSnapshotsViewerTests/MenuPresenterSpec.swift @@ -38,7 +38,7 @@ class MenuPresenterSpec: QuickSpec { var updater: UpdaterMock! beforeEach { - build = Build(date: Date(), applicationName: "FBSnapshotsViewer") + build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) updater = UpdaterMock() derivedDataFolder = DerivedDataFolder.xcodeCustom(path: "Users/antondomashnev/Library/Xcode/temporaryFolder") configuration = FBSnapshotsViewer.Configuration(derivedDataFolder: derivedDataFolder) @@ -58,7 +58,7 @@ class MenuPresenterSpec: QuickSpec { } it("checks for updaters") { - expect(updater.checkForUpdatesCalled).to(beTrue()) + expect(updater.checkForUpdates_Called).to(beTrue()) } } @@ -78,7 +78,7 @@ class MenuPresenterSpec: QuickSpec { } it("starts the Xcode builds listening") { - expect(interactor.startXcodeBuildsListeningReceivedDerivedDataFolder).to(equal(derivedDataFolder)) + expect(interactor.startXcodeBuildsListening_derivedDataFolder_ReceivedDerivedDataFolder).to(equal(derivedDataFolder)) } } @@ -88,7 +88,7 @@ class MenuPresenterSpec: QuickSpec { } it("terminates the app") { - expect(application.terminateCalled).to(beTrue()) + expect(application.terminate___Called).to(beTrue()) } } @@ -98,7 +98,7 @@ class MenuPresenterSpec: QuickSpec { } it("pop ups the menu in user interface") { - expect(userInterface.popUpOptionsMenuCalled).to(beTrue()) + expect(userInterface.popUpOptionsMenu_Called).to(beTrue()) } } @@ -108,19 +108,19 @@ class MenuPresenterSpec: QuickSpec { } it("starts listening for snapshot tests results from the given test log") { - expect(interactor.startSnapshotTestResultListeningCalled).to(beTrue()) - expect(interactor.startSnapshotTestResultListeningReceivedPath).to(equal("/Users/antondomashnev/Library/Xcode/Logs/MyLog.log")) + expect(interactor.startSnapshotTestResultListening_fromLogFileAt_Called).to(beTrue()) + expect(interactor.startSnapshotTestResultListening_fromLogFileAt_ReceivedPath).to(equal("/Users/antondomashnev/Library/Xcode/Logs/MyLog.log")) } } describe(".didFindNewTestResult") { beforeEach { - presenter.didFindNewTestResult(SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build)) + presenter.didFindNewTestResult(SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build)) } it("sets that new test results are available in user interface") { - expect(userInterface.setNewTestResultsReceivedAvailable).to(beTrue()) - expect(userInterface.setNewTestResultsCalled).to(beTrue()) + expect(userInterface.setNewTestResults_available_Called).to(beTrue()) + expect(userInterface.setNewTestResults_available_ReceivedAvailable).to(beTrue()) } } @@ -129,18 +129,18 @@ class MenuPresenterSpec: QuickSpec { var foundTestResults: [SnapshotTestResult] = [] beforeEach { - foundTestResults = [SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build)] + foundTestResults = [SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build)] interactor.foundTestResults = foundTestResults presenter.showTestResults() } it("sets that there no new test results in user interface") { - expect(userInterface.setNewTestResultsCalled).to(beTrue()) - expect(userInterface.setNewTestResultsReceivedAvailable).to(beFalse()) + expect(userInterface.setNewTestResults_available_Called).to(beTrue()) + expect(userInterface.setNewTestResults_available_ReceivedAvailable).to(beFalse()) } it("shows test results") { - let expectedPaameter = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build) + let expectedPaameter = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build) expect(wireframe.showTestResultsModuleCalled).to(beTrue()) expect(wireframe.showTestResultsModuleReceivedParameters[0]).to(equal(expectedPaameter)) } @@ -152,7 +152,7 @@ class MenuPresenterSpec: QuickSpec { } it("doesn't update user interface") { - expect(userInterface.setNewTestResultsCalled).to(beFalse()) + expect(userInterface.setNewTestResults_available_Called).to(beFalse()) } it("doesn't show test results") { diff --git a/FBSnapshotsViewerTests/MenuWireframeSpec.swift b/FBSnapshotsViewerTests/MenuWireframeSpec.swift index ac6ba3e..57c33fe 100644 --- a/FBSnapshotsViewerTests/MenuWireframeSpec.swift +++ b/FBSnapshotsViewerTests/MenuWireframeSpec.swift @@ -51,7 +51,7 @@ class MenuWireframeSpec: QuickSpec { beforeEach { let configuration = Configuration.default() configurationStorage = ConfigurationStorageMock() - configurationStorage.loadConfigurationReturnValue = configuration + configurationStorage.loadConfiguration_ReturnValue = configuration } it("doesnt crash") { diff --git a/FBSnapshotsViewerTests/NonRecursiveFolderEventsListenerSpec.swift b/FBSnapshotsViewerTests/NonRecursiveFolderEventsListenerSpec.swift index 993598f..37bf9b2 100644 --- a/FBSnapshotsViewerTests/NonRecursiveFolderEventsListenerSpec.swift +++ b/FBSnapshotsViewerTests/NonRecursiveFolderEventsListenerSpec.swift @@ -93,12 +93,12 @@ class NonRecursiveFolderEventsListenerSpec: QuickSpec { } it("outputs folder event") { - expect(output.folderEventsListenerCalled).to(beTrue()) + expect(output.folderEventsListener___didReceive_Called).to(beTrue()) } it("outputs correct folder event") { let expectedFolderEvent = FolderEvent.created(path: "/path/to/event/file.txt", object: .file) - expect(output.folderEventsListenerReceivedArguments?.1).to(equal(expectedFolderEvent)) + expect(output.folderEventsListener___didReceive_ReceivedArguments?.1).to(equal(expectedFolderEvent)) } } @@ -115,12 +115,12 @@ class NonRecursiveFolderEventsListenerSpec: QuickSpec { } it("outputs folder event") { - expect(output.folderEventsListenerCalled).to(beTrue()) + expect(output.folderEventsListener___didReceive_Called).to(beTrue()) } it("outputs correct folder event") { let expectedFolderEvent = FolderEvent.created(path: "/path/to/event/file.txt", object: .file) - expect(output.folderEventsListenerReceivedArguments?.1).to(equal(expectedFolderEvent)) + expect(output.folderEventsListener___didReceive_ReceivedArguments?.1).to(equal(expectedFolderEvent)) } } @@ -136,7 +136,7 @@ class NonRecursiveFolderEventsListenerSpec: QuickSpec { } it("doesn't output folder event") { - expect(output.folderEventsListenerCalled).to(beFalse()) + expect(output.folderEventsListener___didReceive_Called).to(beFalse()) } } } diff --git a/FBSnapshotsViewerTests/PreferencesControllerSpec.swift b/FBSnapshotsViewerTests/PreferencesControllerSpec.swift index 9f92177..282ea9e 100644 --- a/FBSnapshotsViewerTests/PreferencesControllerSpec.swift +++ b/FBSnapshotsViewerTests/PreferencesControllerSpec.swift @@ -29,7 +29,7 @@ class PreferencesControllerSpec: QuickSpec { } it("updates user interface") { - expect(eventHandler.updateUserInterfaceCalled).to(beTrue()) + expect(eventHandler.updateUserInterface_Called).to(beTrue()) } } @@ -39,7 +39,7 @@ class PreferencesControllerSpec: QuickSpec { } it("closes") { - expect(eventHandler.closeCalled).to(beTrue()) + expect(eventHandler.close_Called).to(beTrue()) } } @@ -68,8 +68,8 @@ class PreferencesControllerSpec: QuickSpec { } it("updates derived data type") { - expect(eventHandler.selectReceivedDerivedDataFolderType).to(equal("Bar")) - expect(eventHandler.selectCalled).to(beTrue()) + expect(eventHandler.select_derivedDataFolderType_ReceivedDerivedDataFolderType).to(equal("Bar")) + expect(eventHandler.select_derivedDataFolderType_Called).to(beTrue()) } } @@ -80,8 +80,8 @@ class PreferencesControllerSpec: QuickSpec { } it("updates derived data path") { - expect(eventHandler.updateReceivedDerivedDataFolderPath).to(equal("NewPath")) - expect(eventHandler.updateCalled).to(beTrue()) + expect(eventHandler.update_derivedDataFolderPath_ReceivedDerivedDataFolderPath).to(equal("NewPath")) + expect(eventHandler.update_derivedDataFolderPath_Called).to(beTrue()) } } } diff --git a/FBSnapshotsViewerTests/PreferencesInteractorSpec.swift b/FBSnapshotsViewerTests/PreferencesInteractorSpec.swift index deec6e9..3f1b2e0 100644 --- a/FBSnapshotsViewerTests/PreferencesInteractorSpec.swift +++ b/FBSnapshotsViewerTests/PreferencesInteractorSpec.swift @@ -28,7 +28,7 @@ class PreferencesInteractorSpec: QuickSpec { beforeEach { newPath = "myNewPath" - configurationStorage.loadConfigurationReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.xcodeCustom(path: "customPath")) + configurationStorage.loadConfiguration_ReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.xcodeCustom(path: "customPath")) interactor = PreferencesInteractor(configurationStorage: configurationStorage) interactor.setNewDerivedDataFolderPath(newPath) } @@ -44,7 +44,7 @@ class PreferencesInteractorSpec: QuickSpec { beforeEach { newPath = "myNewPath" - configurationStorage.loadConfigurationReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.appcode(path: "customPath")) + configurationStorage.loadConfiguration_ReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.appcode(path: "customPath")) interactor = PreferencesInteractor(configurationStorage: configurationStorage) interactor.setNewDerivedDataFolderPath(newPath) } @@ -57,7 +57,7 @@ class PreferencesInteractorSpec: QuickSpec { context("when current configuration derived data folder type is xcodeDefault") { beforeEach { - configurationStorage.loadConfigurationReturnValue = configuration + configurationStorage.loadConfiguration_ReturnValue = configuration interactor = PreferencesInteractor(configurationStorage: configurationStorage) } @@ -70,7 +70,7 @@ class PreferencesInteractorSpec: QuickSpec { describe(".setNewDerivedDataFolderType") { context("when type is not derived data folder type") { beforeEach { - configurationStorage.loadConfigurationReturnValue = configuration + configurationStorage.loadConfiguration_ReturnValue = configuration interactor = PreferencesInteractor(configurationStorage: configurationStorage) } @@ -81,7 +81,7 @@ class PreferencesInteractorSpec: QuickSpec { context("when type is equal to current one") { beforeEach { - configurationStorage.loadConfigurationReturnValue = configuration + configurationStorage.loadConfiguration_ReturnValue = configuration interactor = PreferencesInteractor(configurationStorage: configurationStorage) } @@ -92,7 +92,7 @@ class PreferencesInteractorSpec: QuickSpec { context("when current type is xcodeDefault") { beforeEach { - configurationStorage.loadConfigurationReturnValue = configuration + configurationStorage.loadConfiguration_ReturnValue = configuration interactor = PreferencesInteractor(configurationStorage: configurationStorage) } @@ -119,7 +119,7 @@ class PreferencesInteractorSpec: QuickSpec { context("when current type is xcodeCustom") { beforeEach { - configurationStorage.loadConfigurationReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.xcodeCustom(path: "myPath")) + configurationStorage.loadConfiguration_ReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.xcodeCustom(path: "myPath")) interactor = PreferencesInteractor(configurationStorage: configurationStorage) } @@ -146,7 +146,7 @@ class PreferencesInteractorSpec: QuickSpec { context("when current type is appcode") { beforeEach { - configurationStorage.loadConfigurationReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.appcode(path: "myPath")) + configurationStorage.loadConfiguration_ReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.appcode(path: "myPath")) interactor = PreferencesInteractor(configurationStorage: configurationStorage) } @@ -174,7 +174,7 @@ class PreferencesInteractorSpec: QuickSpec { describe(".currentConfiguration") { beforeEach { - configurationStorage.loadConfigurationReturnValue = configuration + configurationStorage.loadConfiguration_ReturnValue = configuration interactor = PreferencesInteractor(configurationStorage: configurationStorage) } @@ -185,21 +185,21 @@ class PreferencesInteractorSpec: QuickSpec { describe(".save") { beforeEach { - configurationStorage.loadConfigurationReturnValue = configuration + configurationStorage.loadConfiguration_ReturnValue = configuration interactor = PreferencesInteractor(configurationStorage: configurationStorage) interactor.save() } it("saves configuration") { - expect(configurationStorage.saveCalled).to(beTrue()) - expect(configurationStorage.saveReceivedConfiguration).to(equal(configuration)) + expect(configurationStorage.save_configuration_Called).to(beTrue()) + expect(configurationStorage.save_configuration_ReceivedConfiguration).to(equal(configuration)) } } describe(".init") { context("when configuration storage can load configuration") { beforeEach { - configurationStorage.loadConfigurationReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.xcodeDefault) + configurationStorage.loadConfiguration_ReturnValue = Configuration(derivedDataFolder: DerivedDataFolder.xcodeDefault) } it("initializes new instance") { diff --git a/FBSnapshotsViewerTests/PreferencesPresenterSpec.swift b/FBSnapshotsViewerTests/PreferencesPresenterSpec.swift index e340de3..a737d7e 100644 --- a/FBSnapshotsViewerTests/PreferencesPresenterSpec.swift +++ b/FBSnapshotsViewerTests/PreferencesPresenterSpec.swift @@ -38,30 +38,30 @@ class PreferencesPresenterSpec: QuickSpec { describe(".selectDerivedDataFolderType") { beforeEach { let configuration = Configuration(derivedDataFolder: DerivedDataFolder.xcodeCustom(path: "myPath")) - interactor.currentConfigurationReturnValue = configuration + interactor.currentConfiguration_ReturnValue = configuration presenter.select(derivedDataFolderType: "Type") } it("passes the message to interactor") { - expect(interactor.setNewDerivedDataFolderTypeCalled).to(beTrue()) - expect(interactor.setNewDerivedDataFolderTypeReceivedType).to(equal("Type")) + expect(interactor.setNewDerivedDataFolderType___Called).to(beTrue()) + expect(interactor.setNewDerivedDataFolderType___ReceivedType).to(equal("Type")) } it("updates user interface") { - expect(userInterface.showCalled).to(beTrue()) + expect(userInterface.show_preferencesDisplayInfo_Called).to(beTrue()) } } describe(".updateDerivedDataFolderPath") { beforeEach { let configuration = Configuration(derivedDataFolder: DerivedDataFolder.xcodeCustom(path: "myPath")) - interactor.currentConfigurationReturnValue = configuration + interactor.currentConfiguration_ReturnValue = configuration presenter.update(derivedDataFolderPath: "newPath") } it("passes the message to interactor") { - expect(interactor.setNewDerivedDataFolderPathCalled).to(beTrue()) - expect(interactor.setNewDerivedDataFolderPathReceivedPath).to(equal("newPath")) + expect(interactor.setNewDerivedDataFolderPath___Called).to(beTrue()) + expect(interactor.setNewDerivedDataFolderPath___ReceivedPath).to(equal("newPath")) } } @@ -71,24 +71,24 @@ class PreferencesPresenterSpec: QuickSpec { } it("saves") { - expect(interactor.saveCalled).to(beTrue()) + expect(interactor.save_Called).to(beTrue()) } it("notifies the module delegate that module will close") { - expect(moduleDelegate.preferencesModuleWillCloseCalled).to(beTrue()) + expect(moduleDelegate.preferencesModuleWillClose___Called).to(beTrue()) } } describe(".updateUserInterface") { beforeEach { let configuration = Configuration(derivedDataFolder: DerivedDataFolder.xcodeCustom(path: "myPath")) - interactor.currentConfigurationReturnValue = configuration + interactor.currentConfiguration_ReturnValue = configuration presenter.updateUserInterface() } it("shows preferences display info in user interface") { - expect(userInterface.showReceivedPreferencesDisplayInfo?.derivedDataFolderPath).to(equal("myPath")) - expect(userInterface.showReceivedPreferencesDisplayInfo?.derivedDataFolderTypeName).to(equal(DerivedDataFolderType.xcodeCustom.rawValue)) + expect(userInterface.show_preferencesDisplayInfo_ReceivedPreferencesDisplayInfo?.derivedDataFolderPath).to(equal("myPath")) + expect(userInterface.show_preferencesDisplayInfo_ReceivedPreferencesDisplayInfo?.derivedDataFolderTypeName).to(equal(DerivedDataFolderType.xcodeCustom.rawValue)) } } } diff --git a/FBSnapshotsViewerTests/PreferencesWireframeSpec.swift b/FBSnapshotsViewerTests/PreferencesWireframeSpec.swift index 6e5887a..7152c20 100644 --- a/FBSnapshotsViewerTests/PreferencesWireframeSpec.swift +++ b/FBSnapshotsViewerTests/PreferencesWireframeSpec.swift @@ -25,7 +25,7 @@ class PreferencesWireframeSpec: QuickSpec { describe(".show") { beforeEach { - configurationStorage.loadConfigurationReturnValue = Configuration.default() + configurationStorage.loadConfiguration_ReturnValue = Configuration.default() } it("returns preferences module") { diff --git a/FBSnapshotsViewerTests/RecursiveFolderEventsListenerSpec.swift b/FBSnapshotsViewerTests/RecursiveFolderEventsListenerSpec.swift index a73cd82..87185aa 100644 --- a/FBSnapshotsViewerTests/RecursiveFolderEventsListenerSpec.swift +++ b/FBSnapshotsViewerTests/RecursiveFolderEventsListenerSpec.swift @@ -147,12 +147,12 @@ class RecursiveFolderEventsListenerSpec: QuickSpec { } it("outputs folder event") { - expect(output.folderEventsListenerCalled).to(beTrue()) + expect(output.folderEventsListener___didReceive_Called).to(beTrue()) } it("outputs correct folder event") { let expectedFolderEvent = FolderEvent.created(path: "/path/to/event/file.txt", object: .file) - expect(output.folderEventsListenerReceivedArguments?.1).to(equal(expectedFolderEvent)) + expect(output.folderEventsListener___didReceive_ReceivedArguments?.1).to(equal(expectedFolderEvent)) } it("doesn't create a new dependent listener") { @@ -177,12 +177,12 @@ class RecursiveFolderEventsListenerSpec: QuickSpec { } it("outputs folder event") { - expect(output.folderEventsListenerCalled).to(beTrue()) + expect(output.folderEventsListener___didReceive_Called).to(beTrue()) } it("outputs correct folder event") { let expectedFolderEvent = FolderEvent.created(path: "/path/to/event/file.txt", object: .file) - expect(output.folderEventsListenerReceivedArguments?.1).to(equal(expectedFolderEvent)) + expect(output.folderEventsListener___didReceive_ReceivedArguments?.1).to(equal(expectedFolderEvent)) } } @@ -202,7 +202,7 @@ class RecursiveFolderEventsListenerSpec: QuickSpec { } it("doesn't output folder event") { - expect(output.folderEventsListenerCalled).to(beFalse()) + expect(output.folderEventsListener___didReceive_Called).to(beFalse()) } } } diff --git a/FBSnapshotsViewerTests/SnapshotTestResultFactorySpec.swift b/FBSnapshotsViewerTests/SnapshotTestResultFactorySpec.swift index 30ba7f7..9a78bf9 100644 --- a/FBSnapshotsViewerTests/SnapshotTestResultFactorySpec.swift +++ b/FBSnapshotsViewerTests/SnapshotTestResultFactorySpec.swift @@ -17,7 +17,7 @@ class SnapshotTestResultFactorySpec: QuickSpec { var factory: SnapshotTestResultFactory! beforeEach { - build = Build(applicationName: "FBSnapshotsViewer") + build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) factory = SnapshotTestResultFactory() } @@ -45,6 +45,18 @@ class SnapshotTestResultFactorySpec: QuickSpec { expect(createdTestResult).to(beNil()) } } + + context("when fb image reference dir log line") { + var createdTestResult: SnapshotTestResult? + + beforeEach { + createdTestResult = factory.createSnapshotTestResult(from: .fbReferenceImageDirMessage(line: "MyApp"), build: build) + } + + it("doesnt create test result") { + expect(createdTestResult).to(beNil()) + } + } context("when reference image saved message log line") { var createdTestResult: SnapshotTestResult! @@ -79,7 +91,7 @@ class SnapshotTestResultFactorySpec: QuickSpec { } it("creates recorded test result") { - let expectedTestResult = SnapshotTestResult.recorded(testName: "FBSnapshotsViewerExampleTests testRecord", referenceImagePath: "/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png", build: build) + let expectedTestResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "FBSnapshotsViewerExampleTests", testName: "testRecord"), referenceImagePath: "/Users/antondomashnev/Work/FBSnapshotsViewerExample/FBSnapshotsViewerExampleTests/ReferenceImages_64/FBSnapshotsViewerExampleTests/testRecord@2x.png", build: build) expect(createdTestResult).to(equal(expectedTestResult)) } } @@ -118,7 +130,7 @@ class SnapshotTestResultFactorySpec: QuickSpec { } it("creates failed test result") { - let expectedTestResult = SnapshotTestResult.failed(testName: "FBSnapshotsViewerExampleTests testFail", referenceImagePath: "/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png", diffImagePath: "/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/diff_testFail@2x.png", failedImagePath: "/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png", build: build) + let expectedTestResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "FBSnapshotsViewerExampleTests", testName: "testFail"), referenceImagePath: "/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/reference_testFail@2x.png", diffImagePath: "/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/diff_testFail@2x.png", failedImagePath: "/Users/antondomashnev/Library/Developer/CoreSimulator/Devices/B1AC0517-7FC0-4B32-8543-9EC263071FE5/data/Containers/Data/Application/8EEE157C-41B9-47F8-8634-CF3D60962E19/tmp/FBSnapshotsViewerExampleTests/failed_testFail@2x.png", build: build) expect(createdTestResult).to(equal(expectedTestResult)) } diff --git a/FBSnapshotsViewerTests/SnapshotTestResultSwapperSpec.swift b/FBSnapshotsViewerTests/SnapshotTestResultSwapperSpec.swift new file mode 100644 index 0000000..5b4b310 --- /dev/null +++ b/FBSnapshotsViewerTests/SnapshotTestResultSwapperSpec.swift @@ -0,0 +1,148 @@ +// +// SnapshotTestResultSwapperSpec.swift +// FBSnapshotsViewerTests +// +// Created by Anton Domashnev on 27.06.17. +// Copyright © 2017 Anton Domashnev. All rights reserved. +// + +import Quick +import Nimble + +@testable import FBSnapshotsViewer + +class SnapshotTestResultSwapper_MockFileManager: FileManager { + enum SnapshotTestResultSwapper_MockFileManagerError: Error { + case sample + } + + var copyItemCalled: Bool = false + var copyItemFromSourceURL: URL? + var copyItemToDestinationURL: URL? + var copyItemThrows: Bool = false + override func copyItem(at srcURL: URL, to dstURL: URL) throws { + if copyItemThrows { + throw SnapshotTestResultSwapper_MockFileManagerError.sample + } + copyItemCalled = true + copyItemFromSourceURL = srcURL + copyItemToDestinationURL = dstURL + } + + var removeItemCalled: Bool = false + var removeItemAtURL: URL? + var removeItemThrows: Bool = false + override func removeItem(at URL: URL) throws { + if removeItemThrows { + throw SnapshotTestResultSwapper_MockFileManagerError.sample + } + removeItemCalled = true + removeItemAtURL = URL + } +} + +class SnapshotTestResultSwapperSpec: QuickSpec { + override func spec() { + var build: Build! + var imageCache: ImageCacheMock! + var swapper: SnapshotTestResultSwapper! + var fileManager: SnapshotTestResultSwapper_MockFileManager! + + beforeEach { + build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "/foo/bar", isDirectory: true)) + fileManager = SnapshotTestResultSwapper_MockFileManager() + imageCache = ImageCacheMock() + swapper = SnapshotTestResultSwapper(fileManager: fileManager, imageCache: imageCache) + } + + describe(".swap") { + var testResult: SnapshotTestResult! + + context("given recorded snapshot test result") { + beforeEach { + testResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "Foo"), referenceImagePath: "Bar", build: build) + } + + it("throws error") { + expect { try swapper.swap(testResult) }.to(throwError()) + } + } + + context("when file manager throws exception") { + beforeEach { + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "DetailsViewController", testName: "testNormalState"), referenceImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/reference_testNormalState@2x.png", diffImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/difftestNormalState@2x.png", failedImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/failed_testNormalState@2x.png", build: build) + fileManager.removeItemThrows = true + } + + it("throws error") { + expect { try swapper.swap(testResult) }.to(throwError()) + } + } + + context("given failed snapshot test result") { + context("with non-retina images") { + beforeEach { + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "DetailsViewController", testName: "testNormalState"), referenceImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/reference_testNormalState.png", diffImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/difftestNormalState@.png", failedImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/failed_testNormalState@.png", build: build) + } + + it("throws error") { + expect { try swapper.swap(testResult) }.to(throwError()) + } + } + + context("with retina images") { + var returnedTestResult: SnapshotTestResult! + + beforeEach { + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "DetailsViewController", testName: "testNormalState"), referenceImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/reference_testNormalState@2x.png", diffImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/difftestNormalState@2x.png", failedImagePath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/failed_testNormalState@2x.png", build: build) + returnedTestResult = try? swapper.swap(testResult) + } + + it("removes current reference images from directory") { + expect(fileManager.removeItemCalled).to(beTrue()) + expect(fileManager.removeItemAtURL).to(equal(URL(fileURLWithPath: "/foo/bar/DetailsViewController/testNormalState@2x.png"))) + } + + it("copies failed snapshot image to the fb reference images directory") { + expect(fileManager.copyItemCalled).to(beTrue()) + expect(fileManager.copyItemFromSourceURL).to(equal(URL(fileURLWithPath: "/Users/antondomashnev/Library/Xcode/tmp/DetailsViewController/failed_testNormalState@2x.png"))) + expect(fileManager.copyItemToDestinationURL).to(equal(URL(fileURLWithPath: "/foo/bar/DetailsViewController/testNormalState@2x.png"))) + } + + it("invalidates cache") { + expect(imageCache.invalidate_Called).to(beTrue()) + } + + it("returns swapped test result") { + let expectedTestResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "DetailsViewController", testName: "testNormalState"), referenceImagePath: "/foo/bar/DetailsViewController/testNormalState@2x.png", build: build) + expect(returnedTestResult).to(equal(expectedTestResult)) + } + } + } + } + + describe(".canSwap") { + var testResult: SnapshotTestResult! + + context("given recorded snapshot test result") { + beforeEach { + testResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "Foo"), referenceImagePath: "Bar", build: build) + } + + it("returns false") { + expect(swapper.canSwap(testResult)).to(beFalse()) + } + } + + context("given failed snapshot test result") { + beforeEach { + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "Foo"), referenceImagePath: "Reference", diffImagePath: "Diff", failedImagePath: "Failed", build: build) + } + + it("returns true") { + expect(swapper.canSwap(testResult)).to(beTrue()) + } + } + } + } +} diff --git a/FBSnapshotsViewerTests/TestResultCellSpec.swift b/FBSnapshotsViewerTests/TestResultCellSpec.swift index 4c5b1b8..afccae5 100644 --- a/FBSnapshotsViewerTests/TestResultCellSpec.swift +++ b/FBSnapshotsViewerTests/TestResultCellSpec.swift @@ -29,8 +29,19 @@ class TestResultCellSpec: QuickSpec { } it("calls delegate") { - expect(delegate.testResultCellCalled).to(beTrue()) - expect(delegate.testResultCellReceivedArguments?.cell).to(equal(cell)) + expect(delegate.testResultCell___viewInKaleidoscopeButtonClicked_Called).to(beTrue()) + expect(delegate.testResultCell___viewInKaleidoscopeButtonClicked_ReceivedArguments?.cell).to(equal(cell)) + } + } + + describe(".swapSnapshotsButtonClicked") { + beforeEach { + cell.swapSnapshotsButtonClicked(NSButton(frame: NSRect.zero)) + } + + it("calls delegate") { + expect(delegate.testResultCell___swapSnapshotsButtonClicked_Called).to(beTrue()) + expect(delegate.testResultCell___swapSnapshotsButtonClicked_ReceivedArguments?.cell).to(equal(cell)) } } } diff --git a/FBSnapshotsViewerTests/TestResultDisplayInfoSpec.swift b/FBSnapshotsViewerTests/TestResultDisplayInfoSpec.swift index 72c30be..f220b13 100644 --- a/FBSnapshotsViewerTests/TestResultDisplayInfoSpec.swift +++ b/FBSnapshotsViewerTests/TestResultDisplayInfoSpec.swift @@ -38,22 +38,34 @@ class TestResultDisplayInfo_MockKaleidoscopeViewer: ExternalViewer { } } +class TestResultDisplayInfo_MockSnapshotTestResultSwapper: SnapshotTestResultSwapper { + var canSwapReturnValue: Bool = false + override func canSwap(_ testResult: SnapshotTestResult) -> Bool { + return canSwapReturnValue + } +} + class TestResultDisplayInfoSpec: QuickSpec { override func spec() { describe(".initWithTestInfo") { var build: Build! var testResult: SnapshotTestResult! + var swapper: TestResultDisplayInfo_MockSnapshotTestResultSwapper! let kaleidoscopeViewer: TestResultDisplayInfo_MockKaleidoscopeViewer.Type = TestResultDisplayInfo_MockKaleidoscopeViewer.self afterEach { kaleidoscopeViewer.reset() } - + + beforeEach { + swapper = TestResultDisplayInfo_MockSnapshotTestResultSwapper() + } + describe("testName") { context("when test name with undrscore") { beforeEach { - build = Build(date: Date(), applicationName: "FBSnapshotsViewer") - testResult = SnapshotTestResult.failed(testName: "TestClass_testName_has_replaced_all_underscore_with_spaces", referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) + build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "TestClass", testName: "testName_has_replaced_all_underscore_with_spaces"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) } it("has correct test name") { @@ -69,7 +81,7 @@ class TestResultDisplayInfoSpec: QuickSpec { context("when test name without undrscore") { beforeEach { - testResult = SnapshotTestResult.failed(testName: "TestClass testName", referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "TestClass", testName: "testName"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) } it("has correct test name") { @@ -83,10 +95,40 @@ class TestResultDisplayInfoSpec: QuickSpec { } } } - + + describe("canBeSwapped") { + var displayInfo: TestResultDisplayInfo! + + beforeEach { + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "TestClass", testName: "testFailed"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) + } + + context("when swapper can swap given test result") { + beforeEach { + swapper.canSwapReturnValue = true + displayInfo = TestResultDisplayInfo(testResult: testResult, swapper: swapper) + } + + it("can be swapped") { + expect(displayInfo.canBeSwapped).to(beTrue()) + } + } + + context("when swapper can not swap given test result") { + beforeEach { + swapper.canSwapReturnValue = false + displayInfo = TestResultDisplayInfo(testResult: testResult, swapper: swapper) + } + + it("can not be swapped") { + expect(displayInfo.canBeSwapped).to(beFalse()) + } + } + } + describe("canBeViewedInKaleidoscope") { beforeEach { - testResult = SnapshotTestResult.failed(testName: "testFailed", referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "TestClass", testName: "testFailed"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) } context("when kaleidoscope viewer is available") { @@ -131,7 +173,7 @@ class TestResultDisplayInfoSpec: QuickSpec { context("when failed test result") { beforeEach { - testResult = SnapshotTestResult.failed(testName: "TestClass testFailed", referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) + testResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "TestClass", testName: "testFailed"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build) } it("initializes object correctly") { @@ -147,7 +189,7 @@ class TestResultDisplayInfoSpec: QuickSpec { context("when recorded test result") { beforeEach { - testResult = SnapshotTestResult.recorded(testName: "ExampleTestClass testRecord", referenceImagePath: "referenceImagePath.png", build: build) + testResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "ExampleTestClass", testName: "testRecord"), referenceImagePath: "referenceImagePath.png", build: build) } it("initializes object correctly") { diff --git a/FBSnapshotsViewerTests/TestResultsCollectionViewOutletsSpec.swift b/FBSnapshotsViewerTests/TestResultsCollectionViewOutletsSpec.swift index ba2e94f..c6ce370 100644 --- a/FBSnapshotsViewerTests/TestResultsCollectionViewOutletsSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsCollectionViewOutletsSpec.swift @@ -19,16 +19,16 @@ class TestResultsCollectionViewOutletsSpec: QuickSpec { var testResultsDisplayInfo: TestResultsDisplayInfo! beforeEach { - let build1 = Build(date: Date(), applicationName: "MyApp") - let snapshotTestResult1 = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build1) + let build1 = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let snapshotTestResult1 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build1) let testResult1 = TestResultDisplayInfo(testResult: snapshotTestResult1) let sectionTitle1 = TestResultsSectionTitleDisplayInfo(build: build1, testContext: "Context1") let section1 = TestResultsSectionDisplayInfo(title: sectionTitle1, items: [testResult1]) - let build2 = Build(date: Date(), applicationName: "MyApp") - let snapshotTestResult2 = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build2) + let build2 = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let snapshotTestResult2 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build2) let testResult2 = TestResultDisplayInfo(testResult: snapshotTestResult2) - let snapshotTestResult3 = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build2) + let snapshotTestResult3 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath.png", diffImagePath: "diffImagePath.png", failedImagePath: "failedImagePath.png", build: build2) let testResult3 = TestResultDisplayInfo(testResult: snapshotTestResult3) let sectionTitle2 = TestResultsSectionTitleDisplayInfo(build: build2, testContext: "Context2") let section2 = TestResultsSectionDisplayInfo(title: sectionTitle2, items: [testResult2, testResult3]) diff --git a/FBSnapshotsViewerTests/TestResultsControllerSpec.swift b/FBSnapshotsViewerTests/TestResultsControllerSpec.swift index ffd152f..0a5cb96 100644 --- a/FBSnapshotsViewerTests/TestResultsControllerSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsControllerSpec.swift @@ -37,12 +37,13 @@ class TestResultsController_MockTestResultsCollectionViewOutlets: TestResultsCol class TestResultsControllerSpec: QuickSpec { override func spec() { - let build: Build = Build(date: Date(), applicationName: "FBSnapshotsViewer") + let build: Build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) var collectionViewOutlets: TestResultsController_MockTestResultsCollectionViewOutlets! var collectionView: TestResultsController_MockNSCollectionView! var controller: TestResultsController! var eventHandler: TestResultsModuleInterfaceMock! var testResults: [TestResultsSectionDisplayInfo] = [] + var testResultDisplayInfo: TestResultDisplayInfo! var topView: TestResultsController_MockTestResultsTopView! var displayInfo: TestResultsDisplayInfo! @@ -57,7 +58,7 @@ class TestResultsControllerSpec: QuickSpec { controller.collectionView = collectionView controller.topView = topView - let testResultDisplayInfo = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testName: "Bla", referenceImagePath: "foo/bar.png", build: build)) + testResultDisplayInfo = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "Bla"), referenceImagePath: "foo/bar.png", build: build)) let titleInfo = TestResultsSectionTitleDisplayInfo(build: build, testContext: "Foo") let sectionInfo = TestResultsSectionDisplayInfo(title: titleInfo, items: [testResultDisplayInfo]) testResults = [sectionInfo] @@ -89,7 +90,7 @@ class TestResultsControllerSpec: QuickSpec { } it("updates user interface") { - expect(eventHandler.updateUserInterfaceCalled).to(beTrue()) + expect(eventHandler.updateUserInterface_Called).to(beTrue()) } } @@ -99,7 +100,51 @@ class TestResultsControllerSpec: QuickSpec { } it("selects diff mode") { - expect(eventHandler.selectDiffModeReceivedDiffMode).to(equal(TestResultsDiffMode.diff)) + expect(eventHandler.selectDiffMode___ReceivedDiffMode).to(equal(TestResultsDiffMode.diff)) + } + } + + describe(".testResultCell:swapSnapshotsButtonClicked") { + var cell: TestResultCell! + var swapSnapshotsButton: NSButton! + + beforeEach { + swapSnapshotsButton = NSButton(frame: NSRect.zero) + cell = TestResultCell(nibName: nil, bundle: nil) + } + + context("when cell is not visible") { + beforeEach { + collectionView.indexPathForItemReturnValue = nil + } + + it("asserts") { + expect { controller.testResultCell(cell, swapSnapshotsButtonClicked: swapSnapshotsButton) }.to(throwAssertion()) + } + } + + context("when test result is not presented in controller") { + beforeEach { + collectionViewOutlets.testResultsDisplayInfo = displayInfo + collectionView.indexPathForItemReturnValue = IndexPath(item: 1, section: 0) + } + + it("asserts") { + expect { controller.testResultCell(cell, swapSnapshotsButtonClicked: swapSnapshotsButton) }.to(throwAssertion()) + } + } + + context("when test result is presented and cell is visible") { + beforeEach { + collectionViewOutlets.testResultsDisplayInfo = displayInfo + collectionView.indexPathForItemReturnValue = IndexPath(item: 0, section: 0) + controller.testResultCell(cell, swapSnapshotsButtonClicked: swapSnapshotsButton) + } + + it("swaps test result") { + expect(eventHandler.swap___Called).to(beTrue()) + expect(eventHandler.swap___ReceivedTestResults).to(equal([testResultDisplayInfo])) + } } } @@ -141,8 +186,8 @@ class TestResultsControllerSpec: QuickSpec { } it("opens test result in kaleidoscope") { - expect(eventHandler.openInKaleidoscopeCalled).to(beTrue()) - expect(eventHandler.openInKaleidoscopeReceivedTestResultDisplayInfo).to(equal(testResults[0].itemInfos[0])) + expect(eventHandler.openInKaleidoscope_testResultDisplayInfo_Called).to(beTrue()) + expect(eventHandler.openInKaleidoscope_testResultDisplayInfo_ReceivedTestResultDisplayInfo).to(equal(testResults[0].itemInfos[0])) } } } diff --git a/FBSnapshotsViewerTests/TestResultsDisplayInfoSpec.swift b/FBSnapshotsViewerTests/TestResultsDisplayInfoSpec.swift index a4d2ba3..1332106 100644 --- a/FBSnapshotsViewerTests/TestResultsDisplayInfoSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsDisplayInfoSpec.swift @@ -18,13 +18,13 @@ class TestResultsDisplayInfoSpec: QuickSpec { describe(".init") { beforeEach { - let build1 = Build(applicationName: "FBSnapshotsViewer") - let build2 = Build(applicationName: "AmazingWeather") - let build3 = Build(applicationName: "FBSnapshotsViewer") - let testResultInfo1 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testName: "foo_name", referenceImagePath: "foo/bar.png", build: build1)) - let testResultInfo2 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testName: "foo_name", referenceImagePath: "foo/bar.png", build: build2)) - let testResultInfo3 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testName: "foo_name", referenceImagePath: "foo/bar.png", build: build3)) - let testResultInfo4 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testName: "foo_name", referenceImagePath: "foo/bar.png", build: build3)) + let build1 = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let build2 = Build(date: Date(), applicationName: "AmazingWeather", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/foo", isDirectory: true)) + let build3 = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let testResultInfo1 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "foo_name"), referenceImagePath: "foo/bar.png", build: build1)) + let testResultInfo2 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "foo_name"), referenceImagePath: "foo/bar.png", build: build2)) + let testResultInfo3 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "foo_name"), referenceImagePath: "foo/bar.png", build: build3)) + let testResultInfo4 = TestResultDisplayInfo(testResult: SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "Bar", testName: "foo_name"), referenceImagePath: "foo/bar.png", build: build3)) let sectionTitleInfo1 = TestResultsSectionTitleDisplayInfo(build: build1, testContext: "context1") let sectionInfo1 = TestResultsSectionDisplayInfo(title: sectionTitleInfo1, items: [testResultInfo1]) let sectionTitleInfo2 = TestResultsSectionTitleDisplayInfo(build: build2, testContext: "context2") diff --git a/FBSnapshotsViewerTests/TestResultsDisplayInfosCollectorSpec.swift b/FBSnapshotsViewerTests/TestResultsDisplayInfosCollectorSpec.swift index 3e8dc9a..1690a38 100644 --- a/FBSnapshotsViewerTests/TestResultsDisplayInfosCollectorSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsDisplayInfosCollectorSpec.swift @@ -15,9 +15,9 @@ class TestResultsDisplayInfosCollectorSpec: QuickSpec { override func spec() { var subject: TestResultsDisplayInfosCollector! var testResults: [SnapshotTestResult] = [] - let build1 = Build(date: Date(timeIntervalSinceNow: -300), applicationName: "FBSnapshotsViewer") - let build2 = Build(date: Date(timeIntervalSinceNow: -500), applicationName: "AmazingWeather") - let build3 = Build(date: Date(timeIntervalSinceNow: -700), applicationName: "FBSnapshotsViewer") + let build1 = Build(date: Date(timeIntervalSinceNow: -300), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let build2 = Build(date: Date(timeIntervalSinceNow: -500), applicationName: "AmazingWeather", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/foo", isDirectory: true)) + let build3 = Build(date: Date(timeIntervalSinceNow: -700), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) beforeEach { subject = TestResultsDisplayInfosCollector() @@ -27,16 +27,17 @@ class TestResultsDisplayInfosCollectorSpec: QuickSpec { var collectedInfos: [TestResultsSectionDisplayInfo] = [] beforeEach { - let testResult1 = SnapshotTestResult.recorded(testName: "MainScreen basicState", referenceImagePath: "foo/bar/basic_state.png", build: build1) - let testResult2 = SnapshotTestResult.recorded(testName: "DetailScreen basicState", referenceImagePath: "foo/bar/detail_state.png", build: build1) - let testResult3 = SnapshotTestResult.failed(testName: "DetailScreen emptyState", referenceImagePath: "foo/bar/empty_state.png", diffImagePath: "foo/bar/diff_empty_state.png", failedImagePath: "foo/bar/failed_empty_state.png", build: build1) - let testResult4 = SnapshotTestResult.recorded(testName: "DetailScreen errorState", referenceImagePath: "foo/bar/error_state.png", build: build1) - let testResult5 = SnapshotTestResult.failed(testName: "MainScreen errorState", referenceImagePath: "foo/bar/error_state.png", diffImagePath: "foo/bar/diff_error_state.png", failedImagePath: "foo/bar/failed_error_state.png", build: build1) - let testResult6 = SnapshotTestResult.failed(testName: "HomeScreen emptyState", referenceImagePath: "foo/bar/empty_state.png", diffImagePath: "foo/bar/diff_empty_state.png", failedImagePath: "foo/bar/failed_empty_state.png", build: build2) - let testResult7 = SnapshotTestResult.recorded(testName: "HomeScreen errorState", referenceImagePath: "foo/bar/error_state.png", build: build2) - let testResult8 = SnapshotTestResult.failed(testName: "SettingsScreen errorState", referenceImagePath: "foo/bar/error_state.png", diffImagePath: "foo/bar/diff_error_state.png", failedImagePath: "foo/bar/failed_error_state.png", build: build2) - let testResult9 = SnapshotTestResult.recorded(testName: "MainScreen basicState", referenceImagePath: "foo/bar/basic_state.png", build: build3) - let testResult10 = SnapshotTestResult.recorded(testName: "DetailScreen basicState", referenceImagePath: "foo/bar/detail_state.png", build: build3) + + let testResult1 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "MainScreen", testName: "basicState"), referenceImagePath: "foo/bar/basic_state.png", build: build1) + let testResult2 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "DetailScreen", testName: "basicState"), referenceImagePath: "foo/bar/detail_state.png", build: build1) + let testResult3 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "DetailScreen", testName: "emptyState"), referenceImagePath: "foo/bar/empty_state.png", diffImagePath: "foo/bar/diff_empty_state.png", failedImagePath: "foo/bar/failed_empty_state.png", build: build1) + let testResult4 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "DetailScreen", testName: "errorState"), referenceImagePath: "foo/bar/error_state.png", build: build1) + let testResult5 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "MainScreen", testName: "errorState"), referenceImagePath: "foo/bar/error_state.png", diffImagePath: "foo/bar/diff_error_state.png", failedImagePath: "foo/bar/failed_error_state.png", build: build1) + let testResult6 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "HomeScreen", testName: "emptyState"), referenceImagePath: "foo/bar/empty_state.png", diffImagePath: "foo/bar/diff_empty_state.png", failedImagePath: "foo/bar/failed_empty_state.png", build: build2) + let testResult7 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "HomeScreen", testName: "errorState"), referenceImagePath: "foo/bar/error_state.png", build: build2) + let testResult8 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "SettingsScreen", testName: "errorState"), referenceImagePath: "foo/bar/error_state.png", diffImagePath: "foo/bar/diff_error_state.png", failedImagePath: "foo/bar/failed_error_state.png", build: build2) + let testResult9 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "MainScreen", testName: "basicState"), referenceImagePath: "foo/bar/basic_state.png", build: build3) + let testResult10 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "DetailScreen", testName: "basicState"), referenceImagePath: "foo/bar/detail_state.png", build: build3) testResults = [testResult1, testResult2, testResult3, testResult4, testResult5, testResult6, testResult7, testResult8, testResult9, testResult10] collectedInfos = subject.collect(testResults: testResults) } diff --git a/FBSnapshotsViewerTests/TestResultsInteractorSpec.swift b/FBSnapshotsViewerTests/TestResultsInteractorSpec.swift index e4d07f6..b2b8fd3 100644 --- a/FBSnapshotsViewerTests/TestResultsInteractorSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsInteractorSpec.swift @@ -11,7 +11,7 @@ import Nimble @testable import FBSnapshotsViewer -class TestResultsInteractor_Mock: ExternalViewer { +class TestResultsInteractor_MockExternalViewer: ExternalViewer { static var name: String { return "" } static var bundleID: String { return "" } @@ -37,25 +37,128 @@ class TestResultsInteractor_Mock: ExternalViewer { } } +class TestResultsInteractor_MockSnapshotTestResultSwapper: SnapshotTestResultSwapper { + var swapThrows: Bool = false + var swapCalled: Bool = false + var swapTestResult: SnapshotTestResult? + var swappedTestResult: SnapshotTestResult! + override func swap(_ testResult: SnapshotTestResult) throws -> SnapshotTestResult { + swapCalled = true + swapTestResult = testResult + if swapThrows { + throw SnapshotTestResultSwapperError.canNotBeSwapped(testResult: testResult) + } + return swappedTestResult + } + + var canSwapReturnValue: Bool = false + override func canSwap(_ testResult: SnapshotTestResult) -> Bool { + return canSwapReturnValue + } +} + class TestResultsInteractorSpec: QuickSpec { override func spec() { - let build: Build = Build(date: Date(), applicationName: "MyApp") - let kaleidoscopeViewer: TestResultsInteractor_Mock.Type = TestResultsInteractor_Mock.self + let build: Build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let kaleidoscopeViewer: TestResultsInteractor_MockExternalViewer.Type = TestResultsInteractor_MockExternalViewer.self var processLauncher: ProcessLauncher! var interactor: TestResultsInteractor! + var output: TestResultsInteractorOutputMock! + var swapper: TestResultsInteractor_MockSnapshotTestResultSwapper! var testResults: [SnapshotTestResult] = [] beforeEach { - let testResult1 = SnapshotTestResult.failed(testName: "testName1", referenceImagePath: "referenceImagePath1", diffImagePath: "diffImagePath1", failedImagePath: "failedImagePath1", build: build) - let testResult2 = SnapshotTestResult.recorded(testName: "testName2", referenceImagePath: "referenceImagePath2", build: build) + let testResult1 = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName1"), referenceImagePath: "referenceImagePath1", diffImagePath: "diffImagePath1", failedImagePath: "failedImagePath1", build: build) + let testResult2 = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName2"), referenceImagePath: "referenceImagePath2", build: build) testResults = [testResult1, testResult2] processLauncher = ProcessLauncher() - interactor = TestResultsInteractor(testResults: testResults, kaleidoscopeViewer: kaleidoscopeViewer, processLauncher: processLauncher) + swapper = TestResultsInteractor_MockSnapshotTestResultSwapper() + swapper.swappedTestResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName1"), referenceImagePath: "referenceImagePath1", build: build) + output = TestResultsInteractorOutputMock() + let builder = TestResultsInteractorBuilder { + $0.testResults = testResults + $0.kaleidoscopeViewer = kaleidoscopeViewer + $0.processLauncher = processLauncher + $0.swapper = swapper + } + interactor = TestResultsInteractor(builder: builder) + interactor.output = output } afterEach { kaleidoscopeViewer.reset() } + + describe(".swap") { + var testResult: SnapshotTestResult! + + beforeEach { + testResult = testResults[0] + } + + context("when test result can not be swapped") { + beforeEach { + swapper.canSwapReturnValue = false + interactor.swap(testResult: testResult) + } + + it("does nothing") { + expect(swapper.swapCalled).to(beFalse()) + } + } + + context("when test result can be swapped") { + beforeEach { + swapper.canSwapReturnValue = true + } + + context("when swap throws") { + beforeEach { + swapper.swapThrows = true + interactor.swap(testResult: testResult) + } + + it("outputs error") { + expect(output.didFailToSwap_testResult_with_Called).to(beTrue()) + } + } + + context("when swap doesn't throw") { + beforeEach { + swapper.swapThrows = false + } + + context("given presented test result") { + beforeEach { + interactor.swap(testResult: testResult) + } + + it("swaps") { + expect(swapper.swapCalled).to(beTrue()) + expect(output.didFailToSwap_testResult_with_Called).toNot(beTrue()) + } + + it("replaces failed test result with recorded") { + let testInformation = SnapshotTestInformation(testClassName: testResult.testClassName, testName: testResult.testName) + let expectedRecordedTestResult = SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: "referenceImagePath1", build: build) + expect(interactor.testResults[0]).to(equal(expectedRecordedTestResult)) + } + } + + context("given not presented test result") { + beforeEach { + let testInformation = SnapshotTestInformation(testClassName: "Foo", testName: "Bar") + let notPresentedTestResult = SnapshotTestResult.failed(testInformation: testInformation, referenceImagePath: "foo/bar@2x.png", diffImagePath: "foo/bar@2x.png", failedImagePath: "foo/bar@2x.png", build: build) + interactor.swap(testResult: notPresentedTestResult) + } + + it("outputs error") { + expect(output.didFailToSwap_testResult_with_Called).to(beTrue()) + } + } + } + } + } describe(".openInKaleidoscope") { context("when kaleidoscope viewer is available") { diff --git a/FBSnapshotsViewerTests/TestResultsPresenterSpec.swift b/FBSnapshotsViewerTests/TestResultsPresenterSpec.swift index bc05bc2..d686e4b 100644 --- a/FBSnapshotsViewerTests/TestResultsPresenterSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsPresenterSpec.swift @@ -20,37 +20,70 @@ class TestResultsPresenter_MockTestResultsDisplayInfosCollector: TestResultsDisp } } +class TestResultsPresenter_MockTestResultsInteractorInputMock: TestResultsInteractorInputMock { + var swapCalledCounter: Int = 0 + override func swap(testResult: SnapshotTestResult) { + super.swap(testResult: testResult) + swapCalledCounter += 1 + } +} + class TestResultsPresenterSpec: QuickSpec { override func spec() { var presenter: TestResultsPresenter! - var interactor: TestResultsInteractorInputMock! + var interactor: TestResultsPresenter_MockTestResultsInteractorInputMock! var userInterface: TestResultsUserInterfaceMock! var testResultsCollector: TestResultsPresenter_MockTestResultsDisplayInfosCollector! beforeEach { testResultsCollector = TestResultsPresenter_MockTestResultsDisplayInfosCollector() - interactor = TestResultsInteractorInputMock() + interactor = TestResultsPresenter_MockTestResultsInteractorInputMock() userInterface = TestResultsUserInterfaceMock() presenter = TestResultsPresenter(testResultsCollector: testResultsCollector) presenter.interactor = interactor presenter.userInterface = userInterface } - + + describe(".swap") { + var testResults: [TestResultDisplayInfo] = [] + + beforeEach { + let build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar")) + let testInformation1 = SnapshotTestInformation(testClassName: "testClassName", testName: "testName1") + let testResult1 = SnapshotTestResult.recorded(testInformation: testInformation1, referenceImagePath: "foo/bar/testName1.png", build: build) + let testResultDisplayInfo1 = TestResultDisplayInfo(testResult: testResult1) + let testInformation2 = SnapshotTestInformation(testClassName: "testClassName", testName: "testName2") + let testResult2 = SnapshotTestResult.recorded(testInformation: testInformation2, referenceImagePath: "foo/bar/testName2.png", build: build) + let testResultDisplayInfo2 = TestResultDisplayInfo(testResult: testResult2) + testResults = [testResultDisplayInfo1, testResultDisplayInfo2] + interactor.testResults = [testResult1, testResult2] + presenter.swap(testResults) + } + + it("swaps all given test results") { + expect(interactor.swapCalledCounter).to(equal(2)) + } + + it("updates user interface") { + expect(userInterface.show_displayInfo_Called).to(beTrue()) + } + } + describe(".openInKaleidoscope") { var testResult: SnapshotTestResult! var testResultDisplayInfo: TestResultDisplayInfo! var build: Build! beforeEach { - build = Build(applicationName: "FBSnapshotsViewer") - testResult = SnapshotTestResult.recorded(testName: "MyTest", referenceImagePath: "foo/bar.png", build: build) + build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + testResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "MyTest"), referenceImagePath: "foo/bar.png", build: build) testResultDisplayInfo = TestResultDisplayInfo(testResult: testResult) presenter.openInKaleidoscope(testResultDisplayInfo: testResultDisplayInfo) } it("passes the message to interactor with correct test result") { - expect(interactor.openInKaleidoscopeCalled).to(beTrue()) - expect(interactor.openInKaleidoscopeReceivedTestResult).to(equal(testResult)) + expect(interactor.openInKaleidoscope_testResult_Called).to(beTrue()) + expect(interactor.openInKaleidoscope_testResult_ReceivedTestResult).to(equal(testResult)) } } @@ -61,7 +94,7 @@ class TestResultsPresenterSpec: QuickSpec { } it("doesn't show test results in user interface") { - expect(userInterface.showCalled).to(beFalse()) + expect(userInterface.show_displayInfo_Called).to(beFalse()) } } @@ -70,8 +103,8 @@ class TestResultsPresenterSpec: QuickSpec { var testResults: [SnapshotTestResult] = [] beforeEach { - let build = Build(applicationName: "FBSnapshotsViewer") - let snapshotTestResult = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build) + let build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let snapshotTestResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build) let titleInfo = TestResultsSectionTitleDisplayInfo(build: build, testContext: "Context") let sectionInfo = TestResultsSectionDisplayInfo(title: titleInfo, items: [TestResultDisplayInfo(testResult: snapshotTestResult)]) testResults = [snapshotTestResult] @@ -82,11 +115,11 @@ class TestResultsPresenterSpec: QuickSpec { } it("shows test results in user interface") { - expect(userInterface.showCalled).to(beTrue()) + expect(userInterface.show_displayInfo_Called).to(beTrue()) } it("shows correct test results in user interface") { - expect(userInterface.showReceivedDisplayInfo).to(equal(expectTestResultsDisplayInfo)) + expect(userInterface.show_displayInfo_ReceivedDisplayInfo).to(equal(expectTestResultsDisplayInfo)) } it("uses collector") { @@ -99,16 +132,16 @@ class TestResultsPresenterSpec: QuickSpec { var testResults: [SnapshotTestResult] = [] beforeEach { - let build = Build(applicationName: "FBSnapshotsViewer") - let snapshotTestResult = SnapshotTestResult.failed(testName: "testName", referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build) + let build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let snapshotTestResult = SnapshotTestResult.failed(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "referenceImagePath", diffImagePath: "diffImagePath", failedImagePath: "failedImagePath", build: build) testResults = [snapshotTestResult] interactor.testResults = testResults presenter.selectDiffMode(TestResultsDiffMode.diff) } it("updates user interface") { - expect(userInterface.showCalled).to(beTrue()) - expect(userInterface.showReceivedDisplayInfo?.testResultsDiffMode).to(equal(TestResultsDiffMode.diff)) + expect(userInterface.show_displayInfo_Called).to(beTrue()) + expect(userInterface.show_displayInfo_ReceivedDisplayInfo?.testResultsDiffMode).to(equal(TestResultsDiffMode.diff)) } } } diff --git a/FBSnapshotsViewerTests/TestResultsSectionDisplayInfoSpec.swift b/FBSnapshotsViewerTests/TestResultsSectionDisplayInfoSpec.swift index 10143e8..381a702 100644 --- a/FBSnapshotsViewerTests/TestResultsSectionDisplayInfoSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsSectionDisplayInfoSpec.swift @@ -20,8 +20,8 @@ class TestResultsSectionDisplayInfoSpec: QuickSpec { var title: TestResultsSectionTitleDisplayInfo! beforeEach { - let build = Build(date: Date(), applicationName: "MyApp") - let testResult = SnapshotTestResult.recorded(testName: "TestName", referenceImagePath: "foo/bar.png", build: build) + let build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + let testResult = SnapshotTestResult.recorded(testInformation: SnapshotTestInformation(testClassName: "testClassName", testName: "testName"), referenceImagePath: "foo/bar.png", build: build) title = TestResultsSectionTitleDisplayInfo(build: build, testContext: "TestContext") items = [TestResultDisplayInfo(testResult: testResult)] displayInfo = TestResultsSectionDisplayInfo(title: title, items: items) @@ -32,5 +32,50 @@ class TestResultsSectionDisplayInfoSpec: QuickSpec { expect(displayInfo.titleInfo).to(equal(title)) } } + + describe(".hasItemsToSwap") { + var build: Build! + var items: [TestResultDisplayInfo] = [] + var title: TestResultsSectionTitleDisplayInfo! + var testInformation: SnapshotTestInformation! + + beforeEach { + testInformation = SnapshotTestInformation(testClassName: "testClassName", testName: "testName") + build = Build(date: Date(), applicationName: "MyApp", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) + title = TestResultsSectionTitleDisplayInfo(build: build, testContext: "TestContext") + } + + context("when there is display info that can be swapped") { + beforeEach { + let testResult1 = SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: "foo1/foo1.png", build: build) + let testResult2 = SnapshotTestResult.failed(testInformation: testInformation, referenceImagePath: "foo/bar.png", diffImagePath: "foo/foo.png", failedImagePath: "bar/bar.png", build: build) + let testResult3 = SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: "foo1/foo3.png", build: build) + items = [TestResultDisplayInfo(testResult: testResult1), + TestResultDisplayInfo(testResult: testResult2), + TestResultDisplayInfo(testResult: testResult3)] + displayInfo = TestResultsSectionDisplayInfo(title: title, items: items) + } + + it("returns true") { + expect(displayInfo.hasItemsToSwap).to(beTrue()) + } + } + + context("when there is no display info that can be swapped") { + beforeEach { + let testResult1 = SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: "foo1/foo1.png", build: build) + let testResult2 = SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: "foo1/foo2.png", build: build) + let testResult3 = SnapshotTestResult.recorded(testInformation: testInformation, referenceImagePath: "foo1/foo3.png", build: build) + items = [TestResultDisplayInfo(testResult: testResult1), + TestResultDisplayInfo(testResult: testResult2), + TestResultDisplayInfo(testResult: testResult3)] + displayInfo = TestResultsSectionDisplayInfo(title: title, items: items) + } + + it("returns false") { + expect(displayInfo.hasItemsToSwap).to(beFalse()) + } + } + } } } diff --git a/FBSnapshotsViewerTests/TestResultsSectionTitleDisplayInfoSpec.swift b/FBSnapshotsViewerTests/TestResultsSectionTitleDisplayInfoSpec.swift index 1172378..2e18b6b 100644 --- a/FBSnapshotsViewerTests/TestResultsSectionTitleDisplayInfoSpec.swift +++ b/FBSnapshotsViewerTests/TestResultsSectionTitleDisplayInfoSpec.swift @@ -25,7 +25,7 @@ class TestResultsSectionTitleDisplayInfoSpec: QuickSpec { var displayInfo: TestResultsSectionTitleDisplayInfo! beforeEach { - build = Build(date: Date(), applicationName: "FBSnapshotsViewer") + build = Build(date: Date(), applicationName: "FBSnapshotsViewer", fbReferenceImageDirectoryURL: URL(fileURLWithPath: "foo/bar", isDirectory: true)) dateFormatter = TestResultsSectionTitleDisplayInfo_MockDateComponentsFormatter() } diff --git a/Vendor/Sourcery/CodeGenerated/AutoEquatable.generated.swift b/Vendor/Sourcery/CodeGenerated/AutoEquatable.generated.swift index a98aa84..8f259c8 100644 --- a/Vendor/Sourcery/CodeGenerated/AutoEquatable.generated.swift +++ b/Vendor/Sourcery/CodeGenerated/AutoEquatable.generated.swift @@ -28,6 +28,14 @@ extension Build: Equatable {} internal func == (lhs: Build, rhs: Build) -> Bool { guard lhs.date == rhs.date else { return false } guard lhs.applicationName == rhs.applicationName else { return false } + guard lhs.fbReferenceImageDirectoryURL == rhs.fbReferenceImageDirectoryURL else { return false } + return true +} +// MARK: - SnapshotTestInformation AutoEquatable +extension SnapshotTestInformation: Equatable {} +internal func == (lhs: SnapshotTestInformation, rhs: SnapshotTestInformation) -> Bool { + guard lhs.testClassName == rhs.testClassName else { return false } + guard lhs.testName == rhs.testName else { return false } return true } // MARK: - TestResultDisplayInfo AutoEquatable @@ -39,6 +47,7 @@ internal func == (lhs: TestResultDisplayInfo, rhs: TestResultDisplayInfo) -> Boo guard lhs.testName == rhs.testName else { return false } guard lhs.testContext == rhs.testContext else { return false } guard lhs.canBeViewedInKaleidoscope == rhs.canBeViewedInKaleidoscope else { return false } + guard lhs.canBeSwapped == rhs.canBeSwapped else { return false } guard lhs.testResult == rhs.testResult else { return false } return true } @@ -88,6 +97,8 @@ internal func == (lhs: ApplicationLogLine, rhs: ApplicationLogLine) -> Bool { return lhs == rhs case (.applicationNameMessage(let lhs), .applicationNameMessage(let rhs)): return lhs == rhs + case (.fbReferenceImageDirMessage(let lhs), .fbReferenceImageDirMessage(let rhs)): + return lhs == rhs case (.unknown, .unknown): return true default: return false @@ -141,12 +152,12 @@ extension SnapshotTestResult: Equatable {} internal func == (lhs: SnapshotTestResult, rhs: SnapshotTestResult) -> Bool { switch (lhs, rhs) { case (.recorded(let lhs), .recorded(let rhs)): - if lhs.testName != rhs.testName { return false } + if lhs.testInformation != rhs.testInformation { return false } if lhs.referenceImagePath != rhs.referenceImagePath { return false } if lhs.build != rhs.build { return false } return true case (.failed(let lhs), .failed(let rhs)): - if lhs.testName != rhs.testName { return false } + if lhs.testInformation != rhs.testInformation { return false } if lhs.referenceImagePath != rhs.referenceImagePath { return false } if lhs.diffImagePath != rhs.diffImagePath { return false } if lhs.failedImagePath != rhs.failedImagePath { return false } diff --git a/Vendor/Sourcery/CodeGenerated/AutoHashable.generated.swift b/Vendor/Sourcery/CodeGenerated/AutoHashable.generated.swift index b41440e..e7b2f31 100644 --- a/Vendor/Sourcery/CodeGenerated/AutoHashable.generated.swift +++ b/Vendor/Sourcery/CodeGenerated/AutoHashable.generated.swift @@ -23,7 +23,7 @@ fileprivate func combineHashValues(_ initial: Int, _ other: Int) -> Int { // MARK: - Build AutoHashable extension Build: Hashable { internal var hashValue: Int { - return combineHashes([date.hashValue, applicationName.hashValue, 0]) + return combineHashes([date.hashValue, applicationName.hashValue, fbReferenceImageDirectoryURL.hashValue, 0]) } } // MARK: - TestResultsSectionTitleDisplayInfo AutoHashable @@ -45,8 +45,10 @@ extension ApplicationLogLine: Hashable { return combineHashes([2, data.hashValue]) case .applicationNameMessage(let data): return combineHashes([3, data.hashValue]) + case .fbReferenceImageDirMessage(let data): + return combineHashes([4, data.hashValue]) case .unknown: - return 4.hashValue + return 5.hashValue } } } diff --git a/Vendor/Sourcery/CodeGenerated/AutoMockable.generated.swift b/Vendor/Sourcery/CodeGenerated/AutoMockable.generated.swift index 0bf9c4e..560497e 100644 --- a/Vendor/Sourcery/CodeGenerated/AutoMockable.generated.swift +++ b/Vendor/Sourcery/CodeGenerated/AutoMockable.generated.swift @@ -1,6 +1,9 @@ // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT +// swiftlint:disable line_length +// swiftlint:disable variable_name + import Foundation #if os(iOS) || os(tvOS) || os(watchOS) import UIKit @@ -14,13 +17,13 @@ class ApplicationMock: Application { //MARK: - terminate - var terminateCalled = false - var terminateReceivedSender: Any? + var terminate___Called = false + var terminate___ReceivedSender: Any? func terminate(_ sender: Any?) { - terminateCalled = true - terminateReceivedSender = sender + terminate___Called = true + terminate___ReceivedSender = sender } } class ApplicationNameExtractorMock: ApplicationNameExtractor { @@ -28,15 +31,15 @@ class ApplicationNameExtractorMock: ApplicationNameExtractor { //MARK: - extractApplicationName - var extractApplicationNameCalled = false - var extractApplicationNameReceivedLogLine: ApplicationLogLine? - var extractApplicationNameReturnValue: String! + var extractApplicationName_from_Called = false + var extractApplicationName_from_ReceivedLogLine: ApplicationLogLine? + var extractApplicationName_from_ReturnValue: String! func extractApplicationName(from logLine: ApplicationLogLine) -> String { - extractApplicationNameCalled = true - extractApplicationNameReceivedLogLine = logLine - return extractApplicationNameReturnValue + extractApplicationName_from_Called = true + extractApplicationName_from_ReceivedLogLine = logLine + return extractApplicationName_from_ReturnValue } } class ConfigurationStorageMock: ConfigurationStorage { @@ -44,23 +47,39 @@ class ConfigurationStorageMock: ConfigurationStorage { //MARK: - loadConfiguration - var loadConfigurationCalled = false - var loadConfigurationReturnValue: Configuration? + var loadConfiguration_Called = false + var loadConfiguration_ReturnValue: Configuration? func loadConfiguration() -> Configuration? { - loadConfigurationCalled = true - return loadConfigurationReturnValue + loadConfiguration_Called = true + return loadConfiguration_ReturnValue } //MARK: - save - var saveCalled = false - var saveReceivedConfiguration: Configuration? + var save_configuration_Called = false + var save_configuration_ReceivedConfiguration: Configuration? func save(configuration: Configuration) { - saveCalled = true - saveReceivedConfiguration = configuration + save_configuration_Called = true + save_configuration_ReceivedConfiguration = configuration + } +} +class FBReferenceImageDirectoryURLExtractorMock: FBReferenceImageDirectoryURLExtractor { + + + //MARK: - extractImageDirectoryURL + + var extractImageDirectoryURL_from_Called = false + var extractImageDirectoryURL_from_ReceivedLogLine: ApplicationLogLine? + var extractImageDirectoryURL_from_ReturnValue: URL! + + func extractImageDirectoryURL(from logLine: ApplicationLogLine) -> URL { + + extractImageDirectoryURL_from_Called = true + extractImageDirectoryURL_from_ReceivedLogLine = logLine + return extractImageDirectoryURL_from_ReturnValue } } class FolderEventsListenerMock: FolderEventsListener { @@ -69,26 +88,26 @@ class FolderEventsListenerMock: FolderEventsListener { //MARK: - init - var initReceivedArguments: (folderPath: String, filter: FolderEventFilter?, fileWatcherFactory: FileWatcherFactory)? + var init_folderPath_filter_fileWatcherFactory_ReceivedArguments: (folderPath: String, filter: FolderEventFilter?, fileWatcherFactory: FileWatcherFactory)? required init(folderPath: String, filter: FolderEventFilter?, fileWatcherFactory: FileWatcherFactory) { - initReceivedArguments = (folderPath: folderPath, filter: filter, fileWatcherFactory: fileWatcherFactory) + init_folderPath_filter_fileWatcherFactory_ReceivedArguments = (folderPath: folderPath, filter: filter, fileWatcherFactory: fileWatcherFactory) } //MARK: - startListening - var startListeningCalled = false + var startListening_Called = false func startListening() { - startListeningCalled = true + startListening_Called = true } //MARK: - stopListening - var stopListeningCalled = false + var stopListening_Called = false func stopListening() { - stopListeningCalled = true + stopListening_Called = true } } class FolderEventsListenerOutputMock: FolderEventsListenerOutput { @@ -96,13 +115,25 @@ class FolderEventsListenerOutputMock: FolderEventsListenerOutput { //MARK: - folderEventsListener - var folderEventsListenerCalled = false - var folderEventsListenerReceivedArguments: (listener: FolderEventsListener, event: FolderEvent)? + var folderEventsListener___didReceive_Called = false + var folderEventsListener___didReceive_ReceivedArguments: (listener: FolderEventsListener, event: FolderEvent)? func folderEventsListener(_ listener: FolderEventsListener, didReceive event: FolderEvent) { - folderEventsListenerCalled = true - folderEventsListenerReceivedArguments = (listener: listener, event: event) + folderEventsListener___didReceive_Called = true + folderEventsListener___didReceive_ReceivedArguments = (listener: listener, event: event) + } +} +class ImageCacheMock: ImageCache { + + + //MARK: - invalidate + + var invalidate_Called = false + + func invalidate() { + + invalidate_Called = true } } class MenuInteractorInputMock: MenuInteractorInput { @@ -111,23 +142,23 @@ class MenuInteractorInputMock: MenuInteractorInput { //MARK: - startXcodeBuildsListening - var startXcodeBuildsListeningCalled = false - var startXcodeBuildsListeningReceivedDerivedDataFolder: DerivedDataFolder? + var startXcodeBuildsListening_derivedDataFolder_Called = false + var startXcodeBuildsListening_derivedDataFolder_ReceivedDerivedDataFolder: DerivedDataFolder? func startXcodeBuildsListening(derivedDataFolder: DerivedDataFolder) { - startXcodeBuildsListeningCalled = true - startXcodeBuildsListeningReceivedDerivedDataFolder = derivedDataFolder + startXcodeBuildsListening_derivedDataFolder_Called = true + startXcodeBuildsListening_derivedDataFolder_ReceivedDerivedDataFolder = derivedDataFolder } //MARK: - startSnapshotTestResultListening - var startSnapshotTestResultListeningCalled = false - var startSnapshotTestResultListeningReceivedPath: String? + var startSnapshotTestResultListening_fromLogFileAt_Called = false + var startSnapshotTestResultListening_fromLogFileAt_ReceivedPath: String? func startSnapshotTestResultListening(fromLogFileAt path: String) { - startSnapshotTestResultListeningCalled = true - startSnapshotTestResultListeningReceivedPath = path + startSnapshotTestResultListening_fromLogFileAt_Called = true + startSnapshotTestResultListening_fromLogFileAt_ReceivedPath = path } } class MenuInteractorOutputMock: MenuInteractorOutput { @@ -135,23 +166,23 @@ class MenuInteractorOutputMock: MenuInteractorOutput { //MARK: - didFindNewTestResult - var didFindNewTestResultCalled = false - var didFindNewTestResultReceivedTestResult: SnapshotTestResult? + var didFindNewTestResult___Called = false + var didFindNewTestResult___ReceivedTestResult: SnapshotTestResult? func didFindNewTestResult(_ testResult: SnapshotTestResult) { - didFindNewTestResultCalled = true - didFindNewTestResultReceivedTestResult = testResult + didFindNewTestResult___Called = true + didFindNewTestResult___ReceivedTestResult = testResult } //MARK: - didFindNewTestLogFile - var didFindNewTestLogFileCalled = false - var didFindNewTestLogFileReceivedPath: String? + var didFindNewTestLogFile_at_Called = false + var didFindNewTestLogFile_at_ReceivedPath: String? func didFindNewTestLogFile(at path: String) { - didFindNewTestLogFileCalled = true - didFindNewTestLogFileReceivedPath = path + didFindNewTestLogFile_at_Called = true + didFindNewTestLogFile_at_ReceivedPath = path } } class MenuModuleInterfaceMock: MenuModuleInterface { @@ -159,51 +190,51 @@ class MenuModuleInterfaceMock: MenuModuleInterface { //MARK: - start - var startCalled = false + var start_Called = false func start() { - startCalled = true + start_Called = true } //MARK: - showTestResults - var showTestResultsCalled = false + var showTestResults_Called = false func showTestResults() { - showTestResultsCalled = true + showTestResults_Called = true } //MARK: - showPreferences - var showPreferencesCalled = false + var showPreferences_Called = false func showPreferences() { - showPreferencesCalled = true + showPreferences_Called = true } //MARK: - showApplicationMenu - var showApplicationMenuCalled = false + var showApplicationMenu_Called = false func showApplicationMenu() { - showApplicationMenuCalled = true + showApplicationMenu_Called = true } //MARK: - checkForUpdates - var checkForUpdatesCalled = false + var checkForUpdates_Called = false func checkForUpdates() { - checkForUpdatesCalled = true + checkForUpdates_Called = true } //MARK: - quit - var quitCalled = false + var quit_Called = false func quit() { - quitCalled = true + quit_Called = true } } class MenuUserInterfaceMock: MenuUserInterface { @@ -211,21 +242,21 @@ class MenuUserInterfaceMock: MenuUserInterface { //MARK: - setNewTestResults - var setNewTestResultsCalled = false - var setNewTestResultsReceivedAvailable: Bool? + var setNewTestResults_available_Called = false + var setNewTestResults_available_ReceivedAvailable: Bool? func setNewTestResults(available: Bool) { - setNewTestResultsCalled = true - setNewTestResultsReceivedAvailable = available + setNewTestResults_available_Called = true + setNewTestResults_available_ReceivedAvailable = available } //MARK: - popUpOptionsMenu - var popUpOptionsMenuCalled = false + var popUpOptionsMenu_Called = false func popUpOptionsMenu() { - popUpOptionsMenuCalled = true + popUpOptionsMenu_Called = true } } class PreferencesInteractorInputMock: PreferencesInteractorInput { @@ -233,41 +264,41 @@ class PreferencesInteractorInputMock: PreferencesInteractorInput { //MARK: - save - var saveCalled = false + var save_Called = false func save() { - saveCalled = true + save_Called = true } //MARK: - currentConfiguration - var currentConfigurationCalled = false - var currentConfigurationReturnValue: Configuration! + var currentConfiguration_Called = false + var currentConfiguration_ReturnValue: Configuration! func currentConfiguration() -> Configuration { - currentConfigurationCalled = true - return currentConfigurationReturnValue + currentConfiguration_Called = true + return currentConfiguration_ReturnValue } //MARK: - setNewDerivedDataFolderType - var setNewDerivedDataFolderTypeCalled = false - var setNewDerivedDataFolderTypeReceivedType: String? + var setNewDerivedDataFolderType___Called = false + var setNewDerivedDataFolderType___ReceivedType: String? func setNewDerivedDataFolderType(_ type: String) { - setNewDerivedDataFolderTypeCalled = true - setNewDerivedDataFolderTypeReceivedType = type + setNewDerivedDataFolderType___Called = true + setNewDerivedDataFolderType___ReceivedType = type } //MARK: - setNewDerivedDataFolderPath - var setNewDerivedDataFolderPathCalled = false - var setNewDerivedDataFolderPathReceivedPath: String? + var setNewDerivedDataFolderPath___Called = false + var setNewDerivedDataFolderPath___ReceivedPath: String? func setNewDerivedDataFolderPath(_ path: String) { - setNewDerivedDataFolderPathCalled = true - setNewDerivedDataFolderPathReceivedPath = path + setNewDerivedDataFolderPath___Called = true + setNewDerivedDataFolderPath___ReceivedPath = path } } class PreferencesModuleDelegateMock: PreferencesModuleDelegate { @@ -275,13 +306,13 @@ class PreferencesModuleDelegateMock: PreferencesModuleDelegate { //MARK: - preferencesModuleWillClose - var preferencesModuleWillCloseCalled = false - var preferencesModuleWillCloseReceivedPreferencesModule: PreferencesModuleInterface? + var preferencesModuleWillClose___Called = false + var preferencesModuleWillClose___ReceivedPreferencesModule: PreferencesModuleInterface? func preferencesModuleWillClose(_ preferencesModule: PreferencesModuleInterface) { - preferencesModuleWillCloseCalled = true - preferencesModuleWillCloseReceivedPreferencesModule = preferencesModule + preferencesModuleWillClose___Called = true + preferencesModuleWillClose___ReceivedPreferencesModule = preferencesModule } } class PreferencesModuleInterfaceMock: PreferencesModuleInterface { @@ -289,39 +320,39 @@ class PreferencesModuleInterfaceMock: PreferencesModuleInterface { //MARK: - close - var closeCalled = false + var close_Called = false func close() { - closeCalled = true + close_Called = true } //MARK: - updateUserInterface - var updateUserInterfaceCalled = false + var updateUserInterface_Called = false func updateUserInterface() { - updateUserInterfaceCalled = true + updateUserInterface_Called = true } //MARK: - select - var selectCalled = false - var selectReceivedDerivedDataFolderType: String? + var select_derivedDataFolderType_Called = false + var select_derivedDataFolderType_ReceivedDerivedDataFolderType: String? func select(derivedDataFolderType: String) { - selectCalled = true - selectReceivedDerivedDataFolderType = derivedDataFolderType + select_derivedDataFolderType_Called = true + select_derivedDataFolderType_ReceivedDerivedDataFolderType = derivedDataFolderType } //MARK: - update - var updateCalled = false - var updateReceivedDerivedDataFolderPath: String? + var update_derivedDataFolderPath_Called = false + var update_derivedDataFolderPath_ReceivedDerivedDataFolderPath: String? func update(derivedDataFolderPath: String) { - updateCalled = true - updateReceivedDerivedDataFolderPath = derivedDataFolderPath + update_derivedDataFolderPath_Called = true + update_derivedDataFolderPath_ReceivedDerivedDataFolderPath = derivedDataFolderPath } } class PreferencesUserInterfaceMock: PreferencesUserInterface { @@ -329,13 +360,13 @@ class PreferencesUserInterfaceMock: PreferencesUserInterface { //MARK: - show - var showCalled = false - var showReceivedPreferencesDisplayInfo: PreferencesDisplayInfo? + var show_preferencesDisplayInfo_Called = false + var show_preferencesDisplayInfo_ReceivedPreferencesDisplayInfo: PreferencesDisplayInfo? func show(preferencesDisplayInfo: PreferencesDisplayInfo) { - showCalled = true - showReceivedPreferencesDisplayInfo = preferencesDisplayInfo + show_preferencesDisplayInfo_Called = true + show_preferencesDisplayInfo_ReceivedPreferencesDisplayInfo = preferencesDisplayInfo } } class TestResultCellDelegateMock: TestResultCellDelegate { @@ -343,13 +374,37 @@ class TestResultCellDelegateMock: TestResultCellDelegate { //MARK: - testResultCell - var testResultCellCalled = false - var testResultCellReceivedArguments: (cell: TestResultCell, viewInKaleidoscopeButtonClicked: NSButton)? + var testResultCell___viewInKaleidoscopeButtonClicked_Called = false + var testResultCell___viewInKaleidoscopeButtonClicked_ReceivedArguments: (cell: TestResultCell, viewInKaleidoscopeButtonClicked: NSButton)? func testResultCell(_ cell: TestResultCell, viewInKaleidoscopeButtonClicked: NSButton) { - testResultCellCalled = true - testResultCellReceivedArguments = (cell: cell, viewInKaleidoscopeButtonClicked: viewInKaleidoscopeButtonClicked) + testResultCell___viewInKaleidoscopeButtonClicked_Called = true + testResultCell___viewInKaleidoscopeButtonClicked_ReceivedArguments = (cell: cell, viewInKaleidoscopeButtonClicked: viewInKaleidoscopeButtonClicked) + } + //MARK: - testResultCell + + var testResultCell___swapSnapshotsButtonClicked_Called = false + var testResultCell___swapSnapshotsButtonClicked_ReceivedArguments: (cell: TestResultCell, swapSnapshotsButtonClicked: NSButton)? + + func testResultCell(_ cell: TestResultCell, swapSnapshotsButtonClicked: NSButton) { + + testResultCell___swapSnapshotsButtonClicked_Called = true + testResultCell___swapSnapshotsButtonClicked_ReceivedArguments = (cell: cell, swapSnapshotsButtonClicked: swapSnapshotsButtonClicked) + } +} +class TestResultsHeaderDelegateMock: TestResultsHeaderDelegate { + + + //MARK: - testResultsHeader + + var testResultsHeader___swapSnapshotsButtonClicked_Called = false + var testResultsHeader___swapSnapshotsButtonClicked_ReceivedArguments: (header: TestResultsHeader, swapSnapshotsButtonClicked: NSButton)? + + func testResultsHeader(_ header: TestResultsHeader, swapSnapshotsButtonClicked: NSButton) { + + testResultsHeader___swapSnapshotsButtonClicked_Called = true + testResultsHeader___swapSnapshotsButtonClicked_ReceivedArguments = (header: header, swapSnapshotsButtonClicked: swapSnapshotsButtonClicked) } } class TestResultsInteractorInputMock: TestResultsInteractorInput { @@ -358,13 +413,37 @@ class TestResultsInteractorInputMock: TestResultsInteractorInput { //MARK: - openInKaleidoscope - var openInKaleidoscopeCalled = false - var openInKaleidoscopeReceivedTestResult: SnapshotTestResult? + var openInKaleidoscope_testResult_Called = false + var openInKaleidoscope_testResult_ReceivedTestResult: SnapshotTestResult? func openInKaleidoscope(testResult: SnapshotTestResult) { - openInKaleidoscopeCalled = true - openInKaleidoscopeReceivedTestResult = testResult + openInKaleidoscope_testResult_Called = true + openInKaleidoscope_testResult_ReceivedTestResult = testResult + } + //MARK: - swap + + var swap_testResult_Called = false + var swap_testResult_ReceivedTestResult: SnapshotTestResult? + + func swap(testResult: SnapshotTestResult) { + + swap_testResult_Called = true + swap_testResult_ReceivedTestResult = testResult + } +} +class TestResultsInteractorOutputMock: TestResultsInteractorOutput { + + + //MARK: - didFailToSwap + + var didFailToSwap_testResult_with_Called = false + var didFailToSwap_testResult_with_ReceivedArguments: (testResult: SnapshotTestResult, error: Error)? + + func didFailToSwap(testResult: SnapshotTestResult, with error: Error) { + + didFailToSwap_testResult_with_Called = true + didFailToSwap_testResult_with_ReceivedArguments = (testResult: testResult, error: error) } } class TestResultsModuleInterfaceMock: TestResultsModuleInterface { @@ -372,31 +451,41 @@ class TestResultsModuleInterfaceMock: TestResultsModuleInterface { //MARK: - updateUserInterface - var updateUserInterfaceCalled = false + var updateUserInterface_Called = false func updateUserInterface() { - updateUserInterfaceCalled = true + updateUserInterface_Called = true } //MARK: - openInKaleidoscope - var openInKaleidoscopeCalled = false - var openInKaleidoscopeReceivedTestResultDisplayInfo: TestResultDisplayInfo? + var openInKaleidoscope_testResultDisplayInfo_Called = false + var openInKaleidoscope_testResultDisplayInfo_ReceivedTestResultDisplayInfo: TestResultDisplayInfo? func openInKaleidoscope(testResultDisplayInfo: TestResultDisplayInfo) { - openInKaleidoscopeCalled = true - openInKaleidoscopeReceivedTestResultDisplayInfo = testResultDisplayInfo + openInKaleidoscope_testResultDisplayInfo_Called = true + openInKaleidoscope_testResultDisplayInfo_ReceivedTestResultDisplayInfo = testResultDisplayInfo } //MARK: - selectDiffMode - var selectDiffModeCalled = false - var selectDiffModeReceivedDiffMode: TestResultsDiffMode? + var selectDiffMode___Called = false + var selectDiffMode___ReceivedDiffMode: TestResultsDiffMode? func selectDiffMode(_ diffMode: TestResultsDiffMode) { - selectDiffModeCalled = true - selectDiffModeReceivedDiffMode = diffMode + selectDiffMode___Called = true + selectDiffMode___ReceivedDiffMode = diffMode + } + //MARK: - swap + + var swap___Called = false + var swap___ReceivedTestResults: [TestResultDisplayInfo]? + + func swap(_ testResults: [TestResultDisplayInfo]) { + + swap___Called = true + swap___ReceivedTestResults = testResults } } class TestResultsUserInterfaceMock: TestResultsUserInterface { @@ -404,13 +493,13 @@ class TestResultsUserInterfaceMock: TestResultsUserInterface { //MARK: - show - var showCalled = false - var showReceivedDisplayInfo: TestResultsDisplayInfo? + var show_displayInfo_Called = false + var show_displayInfo_ReceivedDisplayInfo: TestResultsDisplayInfo? func show(displayInfo: TestResultsDisplayInfo) { - showCalled = true - showReceivedDisplayInfo = displayInfo + show_displayInfo_Called = true + show_displayInfo_ReceivedDisplayInfo = displayInfo } } class UpdaterMock: Updater { @@ -418,10 +507,10 @@ class UpdaterMock: Updater { //MARK: - checkForUpdates - var checkForUpdatesCalled = false + var checkForUpdates_Called = false func checkForUpdates() { - checkForUpdatesCalled = true + checkForUpdates_Called = true } } diff --git a/Vendor/Sourcery/Templates/AutoMockable.stencil b/Vendor/Sourcery/Templates/AutoMockable.stencil index efddfc1..532b63a 100644 --- a/Vendor/Sourcery/Templates/AutoMockable.stencil +++ b/Vendor/Sourcery/Templates/AutoMockable.stencil @@ -1,3 +1,6 @@ +// swiftlint:disable line_length +// swiftlint:disable variable_name + import Foundation #if os(iOS) || os(tvOS) || os(watchOS) import UIKit @@ -7,10 +10,10 @@ import AppKit {% macro methodReceivedParameters method %} {%if method.parameters.count == 1 %} - {{ method.shortName }}Received{% for param in method.parameters %}{{ param.name|upperFirst }} = {{ param.name }}{% endfor %} + {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}Received{% for param in method.parameters %}{{ param.name|upperFirst }} = {{ param.name }}{% endfor %} {% else %} {% if not method.parameters.count == 0 %} - {{ method.shortName }}ReceivedArguments = ({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %}) + {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}ReceivedArguments = ({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %}) {% endif %} {% endif %} {% endmacro %} @@ -26,13 +29,13 @@ class {{ type.name }}Mock: {{ type.name }} { {% for method in type.allMethods %} //MARK: - {{ method.shortName }} - {% if not method.isInitializer %}var {{ method.shortName }}Called = false{% endif %} + {% if not method.isInitializer %}var {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}Called = false{% endif %} {% if method.parameters.count == 1 %} - var {{ method.shortName }}Received{% for param in method.parameters %}{{ param.name|upperFirst }}: {{ param.typeName.unwrappedTypeName }}?{% endfor %} + var {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}Received{% for param in method.parameters %}{{ param.name|upperFirst }}: {{ param.typeName.unwrappedTypeName }}?{% endfor %} {% else %}{% if not method.parameters.count == 0 %} - var {{ method.shortName }}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{{ param.unwrappedTypeName }}{% else %}{{ param.typeName }}{% endif %}{% if not forloop.last %}, {% endif %}{% endfor %})? + var {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{{ param.unwrappedTypeName }}{% else %}{{ param.typeName }}{% endif %}{% if not forloop.last %}, {% endif %}{% endfor %})? {% endif %}{% endif %} - {% if not method.returnTypeName.isVoid and not method.isInitializer %}var {{ method.shortName }}ReturnValue: {{ method.returnTypeName }}{% if not method.returnTypeName.isOptional %}!{% endif %}{% endif %} + {% if not method.returnTypeName.isVoid and not method.isInitializer %}var {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}ReturnValue: {{ method.returnTypeName }}{% if not method.returnTypeName.isOptional %}!{% endif %}{% endif %} {% if method.isInitializer %} required {{ method.name }} { @@ -41,9 +44,9 @@ class {{ type.name }}Mock: {{ type.name }} { {% else %} func {{ method.name }}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} { - {{ method.shortName }}Called = true + {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}Called = true {% call methodReceivedParameters method %} - {% if not method.returnTypeName.isVoid %}return {{ method.shortName }}ReturnValue{% endif %} + {% if not method.returnTypeName.isVoid %}return {{ method.selectorName | replace:"(","_" | replace:")","" | replace:":","_" }}ReturnValue{% endif %} } {% endif %} {% endfor %}