refactor: Pull out seek back calculation into testable class

This commit is contained in:
ronaldheft 2022-09-20 18:32:28 -04:00
parent 3b285db21a
commit 890852bef5
No known key found for this signature in database
4 changed files with 260 additions and 1 deletions

View file

@ -59,10 +59,22 @@
E9D5507328AC218300C746DD /* DaoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D5507228AC218300C746DD /* DaoExtensions.swift */; };
E9D5507528AEF93100C746DD /* PlayerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D5507428AEF93100C746DD /* PlayerSettings.swift */; };
E9DFCBFB28C28F4A00B36356 /* AudioPlayerSleepTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */; };
E9E8814A28DA644F00D750C1 /* PlayerTimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E8814928DA644F00D750C1 /* PlayerTimeUtils.swift */; };
E9E8814D28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E8814C28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift */; };
E9E985F828B02D9400957F23 /* PlayerProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E985F728B02D9400957F23 /* PlayerProgress.swift */; };
E9FA07E328C82848005520B0 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9FA07E228C82848005520B0 /* Logger.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
E9E8813E28DA5DE500D750C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 504EC2FC1FED79650016851F /* Project object */;
proxyType = 1;
remoteGlobalIDString = 504EC3031FED79650016851F;
remoteInfo = Audiobookshelf;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = "<group>"; };
@ -122,6 +134,9 @@
E9D5507228AC218300C746DD /* DaoExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaoExtensions.swift; sourceTree = "<group>"; };
E9D5507428AEF93100C746DD /* PlayerSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerSettings.swift; sourceTree = "<group>"; };
E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerSleepTimer.swift; sourceTree = "<group>"; };
E9E8813A28DA5DE500D750C1 /* AudiobookshelfUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AudiobookshelfUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E9E8814928DA644F00D750C1 /* PlayerTimeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTimeUtils.swift; sourceTree = "<group>"; };
E9E8814C28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTimeUtilsTests.swift; sourceTree = "<group>"; };
E9E985F728B02D9400957F23 /* PlayerProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerProgress.swift; sourceTree = "<group>"; };
E9FA07E228C82848005520B0 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
@ -136,6 +151,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
E9E8813728DA5DE500D750C1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@ -150,6 +172,7 @@
3ABF6190280432610070250E /* player */ = {
isa = PBXGroup;
children = (
E9E8814828DA641B00D750C1 /* util */,
3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */,
E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */,
3ABF618E2804325C0070250E /* PlayerHandler.swift */,
@ -220,6 +243,7 @@
children = (
3AC8248B27F2316900529205 /* Shared */,
504EC3061FED79650016851F /* App */,
E9E8813B28DA5DE500D750C1 /* AudiobookshelfUnitTests */,
504EC3051FED79650016851F /* Products */,
7F8756D8B27F46E3366F6CEA /* Pods */,
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
@ -230,6 +254,7 @@
isa = PBXGroup;
children = (
504EC3041FED79650016851F /* Audiobookshelf.app */,
E9E8813A28DA5DE500D750C1 /* AudiobookshelfUnitTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -302,6 +327,46 @@
path = download;
sourceTree = "<group>";
};
E9E8813B28DA5DE500D750C1 /* AudiobookshelfUnitTests */ = {
isa = PBXGroup;
children = (
E9E8814328DA5E5900D750C1 /* Shared */,
);
path = AudiobookshelfUnitTests;
sourceTree = "<group>";
};
E9E8814328DA5E5900D750C1 /* Shared */ = {
isa = PBXGroup;
children = (
E9E8814428DA5E6000D750C1 /* player */,
);
path = Shared;
sourceTree = "<group>";
};
E9E8814428DA5E6000D750C1 /* player */ = {
isa = PBXGroup;
children = (
E9E8814B28DA6B6B00D750C1 /* util */,
);
path = player;
sourceTree = "<group>";
};
E9E8814828DA641B00D750C1 /* util */ = {
isa = PBXGroup;
children = (
E9E8814928DA644F00D750C1 /* PlayerTimeUtils.swift */,
);
path = util;
sourceTree = "<group>";
};
E9E8814B28DA6B6B00D750C1 /* util */ = {
isa = PBXGroup;
children = (
E9E8814C28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift */,
);
path = util;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -324,13 +389,31 @@
productReference = 504EC3041FED79650016851F /* Audiobookshelf.app */;
productType = "com.apple.product-type.application";
};
E9E8813928DA5DE500D750C1 /* AudiobookshelfUnitTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = E9E8814228DA5DE500D750C1 /* Build configuration list for PBXNativeTarget "AudiobookshelfUnitTests" */;
buildPhases = (
E9E8813628DA5DE500D750C1 /* Sources */,
E9E8813728DA5DE500D750C1 /* Frameworks */,
E9E8813828DA5DE500D750C1 /* Resources */,
);
buildRules = (
);
dependencies = (
E9E8813F28DA5DE500D750C1 /* PBXTargetDependency */,
);
name = AudiobookshelfUnitTests;
productName = AudiobookshelfUnitTests;
productReference = E9E8813A28DA5DE500D750C1 /* AudiobookshelfUnitTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
504EC2FC1FED79650016851F /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 920;
LastSwiftUpdateCheck = 1400;
LastUpgradeCheck = 1330;
TargetAttributes = {
504EC3031FED79650016851F = {
@ -338,6 +421,11 @@
LastSwiftMigration = 1240;
ProvisioningStyle = Automatic;
};
E9E8813928DA5DE500D750C1 = {
CreatedOnToolsVersion = 14.0;
ProvisioningStyle = Automatic;
TestTargetID = 504EC3031FED79650016851F;
};
};
};
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
@ -354,6 +442,7 @@
projectRoot = "";
targets = (
504EC3031FED79650016851F /* Audiobookshelf */,
E9E8813928DA5DE500D750C1 /* AudiobookshelfUnitTests */,
);
};
/* End PBXProject section */
@ -372,6 +461,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
E9E8813828DA5DE500D750C1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@ -460,13 +556,30 @@
3AF1970C2806E2590096F747 /* ApiClient.swift in Sources */,
4D66B954282EE87C008272D4 /* AbsDownloader.swift in Sources */,
E9D5505628AC1BFA00C746DD /* FileMetadata.swift in Sources */,
E9E8814A28DA644F00D750C1 /* PlayerTimeUtils.swift in Sources */,
3AB34055280832720039308B /* PlayerEvents.swift in Sources */,
E9D5506C28AC1E2100C746DD /* LocalMediaProgress.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E9E8813628DA5DE500D750C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E9E8814D28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
E9E8813F28DA5DE500D750C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 504EC3031FED79650016851F /* Audiobookshelf */;
targetProxy = E9E8813E28DA5DE500D750C1 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
504EC30B1FED79650016851F /* Main.storyboard */ = {
isa = PBXVariantGroup;
@ -646,6 +759,49 @@
};
name = Release;
};
E9E8814028DA5DE500D750C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.AudiobookshelfUnitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Audiobookshelf.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Audiobookshelf";
};
name = Debug;
};
E9E8814128DA5DE500D750C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.AudiobookshelfUnitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Audiobookshelf.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Audiobookshelf";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -667,6 +823,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
E9E8814228DA5DE500D750C1 /* Build configuration list for PBXNativeTarget "AudiobookshelfUnitTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E9E8814028DA5DE500D750C1 /* Debug */,
E9E8814128DA5DE500D750C1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 504EC2FC1FED79650016851F /* Project object */;

View file

@ -28,6 +28,17 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E9E8813928DA5DE500D750C1"
BuildableName = "AudiobookshelfUnitTests.xctest"
BlueprintName = "AudiobookshelfUnitTests"
ReferencedContainer = "container:App.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction

View file

@ -0,0 +1,37 @@
//
// PlayerTimeUtilsTests.swift
// AudiobookshelfUnitTests
//
// Created by Ron Heft on 9/20/22.
//
import XCTest
@testable import Audiobookshelf
final class PlayerTimeUtilsTests: XCTestCase {
func testCalcSeekBackTime() {
let currentTime: Double = 1000
let threeSecondsAgo = Date(timeIntervalSinceNow: -3)
let lastPlayedMs = threeSecondsAgo.timeIntervalSince1970 * 1000
XCTAssertEqual(PlayerTimeUtils.calcSeekBackTime(currentTime: currentTime, lastPlayedMs: lastPlayedMs), 998)
}
func testTimeSinceLastPlayed() throws {
let fiveSecondsAgo = Date(timeIntervalSinceNow: -5)
let lastPlayedMs = fiveSecondsAgo.timeIntervalSince1970 * 1000
XCTAssertEqual(PlayerTimeUtils.timeSinceLastPlayed(lastPlayedMs)!, -5, accuracy: 1.0)
XCTAssertNil(PlayerTimeUtils.timeSinceLastPlayed(nil))
}
func testTimeToSeekBackForSinceLastPlayed() throws {
XCTAssertEqual(PlayerTimeUtils.timeToSeekBackForSinceLastPlayed(nil), 5, "Seeks back 5 seconds for nil")
XCTAssertEqual(PlayerTimeUtils.timeToSeekBackForSinceLastPlayed(5), 2, "Seeks back 2 seconds for less than 6 seconds")
XCTAssertEqual(PlayerTimeUtils.timeToSeekBackForSinceLastPlayed(11), 10, "Seeks back 10 seconds for less than 12 seconds")
XCTAssertEqual(PlayerTimeUtils.timeToSeekBackForSinceLastPlayed(29), 15, "Seeks back 15 seconds for less than 30 seconds")
XCTAssertEqual(PlayerTimeUtils.timeToSeekBackForSinceLastPlayed(179), 20, "Seeks back 20 seconds for less than 2 minutes")
XCTAssertEqual(PlayerTimeUtils.timeToSeekBackForSinceLastPlayed(3599), 25, "Seeks back 25 seconds for less than 59 minutes")
XCTAssertEqual(PlayerTimeUtils.timeToSeekBackForSinceLastPlayed(60000), 29, "Seeks back 29 seconds for anything over 59 minuts")
}
}

View file

@ -0,0 +1,46 @@
//
// PlayerTimeUtils.swift
// Audiobookshelf
//
// Created by Ron Heft on 9/20/22.
//
import Foundation
class PlayerTimeUtils {
private init() {}
static func calcSeekBackTime(currentTime: TimeInterval, lastPlayedMs: Double?) -> TimeInterval {
let sinceLastPlayed = timeSinceLastPlayed(lastPlayedMs)
let timeToSeekBack = timeToSeekBackForSinceLastPlayed(sinceLastPlayed)
return currentTime.advanced(by: -timeToSeekBack)
}
static internal func timeSinceLastPlayed(_ lastPlayedMs: Double?) -> TimeInterval? {
guard let lastPlayedMs = lastPlayedMs else { return nil }
let lastPlayed = Date(timeIntervalSince1970: lastPlayedMs / 1000)
return lastPlayed.timeIntervalSinceNow
}
static internal func timeToSeekBackForSinceLastPlayed(_ sinceLastPlayed: TimeInterval?) -> TimeInterval {
if let sinceLastPlayed = sinceLastPlayed {
if sinceLastPlayed < 6 {
return 2
} else if sinceLastPlayed < 12 {
return 10
} else if sinceLastPlayed < 30 {
return 15
} else if sinceLastPlayed < 180 {
return 20
} else if sinceLastPlayed < 3600 {
return 25
} else {
return 29
}
} else {
return 5
}
}
}