diff --git a/.codecov.yml b/.codecov.yml
deleted file mode 100644
index cd68870..0000000
--- a/.codecov.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-coverage:
- status:
- patch: on
-
-ignore:
- - Tests/**/*
diff --git a/.slather.yml b/.slather.yml
new file mode 100644
index 0000000..4cf7de0
--- /dev/null
+++ b/.slather.yml
@@ -0,0 +1,5 @@
+coverage_service: coveralls
+xcodeproj: Queuer.xcodeproj
+scheme: Queuer iOS
+ignore:
+ - Tests/*
diff --git a/.swift-version b/.swift-version
index 7d5c902..bf77d54 100644
--- a/.swift-version
+++ b/.swift-version
@@ -1 +1 @@
-4.1
+4.2
diff --git a/.travis.yml b/.travis.yml
index 92d3df6..1e63593 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,56 +14,60 @@ matrix:
env: SPM="YES"
- os: osx
language: objective-c
- osx_image: xcode9.4
+ osx_image: xcode10
env: SPM="YES"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.4,name=iPhone X" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="YES"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=12.0,name=iPhone X" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="YES"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.1,name=iPhone 7 Plus" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="YES" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.4,name=iPhone 7 Plus" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="YES" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.3.1,name=iPhone 6" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.3.1,name=iPhone 6" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=iPhone 5s" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=iPhone 5s" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
osx_image: xcode9.2
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO"
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.2,name=Apple TV 4K" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=12.0,name=Apple TV 4K" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.2,name=Apple TV 4K" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=4.2,name=Apple Watch Series 3 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=5.0,name=Apple Watch Series 4 - 44mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="OS=2.0,name=Apple Watch - 38mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=4.2,name=Apple Watch Series 3 - 38mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO"
- os: osx
language: objective-c
- osx_image: xcode9.4
- env: PROJ="Queuer.xcodeproj" DESTINATION="arch=x86_64" SCHEME="$MACOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO"
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO"
+ - os: osx
+ language: objective-c
+ osx_image: xcode10
+ env: PROJ="Queuer.xcodeproj" DESTINATION="arch=x86_64" SCHEME="$MACOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO"
before_install:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
@@ -71,11 +75,12 @@ before_install:
gem install cocoapods --pre --no-rdoc --no-ri --no-document;
brew update;
brew outdated carthage || brew upgrade carthage;
+ gem install slather;
fi
install:
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then
- eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/02090c7ede5a637b76e6df1710e83cd0bbe7dcdf/swiftenv-install.sh)";
+ eval "$(curl -sL https://swiftenv.fuller.li/install.sh)";
fi
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
./install_swiftlint.sh;
@@ -87,8 +92,9 @@ script:
- swift -version
- if [ "$SPM" == "YES" ]; then
- swift build;
- swift test --parallel;
+ swift package clean;
+ ruby generate_linux_tests.rb;
+ swift test;
fi
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
@@ -110,6 +116,6 @@ script:
fi
after_success:
- - if [ "$CODECOV" == "YES" ]; then
- bash <(curl -s https://codecov.io/bash) -X xcodeplist;
+ - if [ "$COVERAGE" == "YES" ]; then
+ slather;
fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3ced009..c3d7b34 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file.
---
+### 2.x Releases
+- `2.0.x` Releases - [2.0.0](#200---let-me-retry)
+
### 1.x Releases
- `1.3.x` Releases - [1.3.0](#130---open-everything) | [1.3.1](#131---swift-41-support) | [1.3.2](#132---linux-quality)
- `1.2.x` Releases - [1.2.0](#120---swift-4-support) | [1.2.1](#121---unwanted-alert)
@@ -16,13 +19,34 @@ All notable changes to this project will be documented in this file.
---
-## Develop
+## [2.0.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.0.0) - Let Me Retry
+### XX XXX 2018
+### Added
+- Added support to Xcode 10 and Swift 4.2
+- Added retry feature to `ConcurrentOperation` class [#10](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10), more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation) and [here](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation)
+- Added `addCompletionHandler(_:)` function to `Queuer` class
+- Added a `Scheduler` class to better schedule your tasks
+
+### Changed
+- Changed watchOS target to watchOS 3.0 instead of 2.0, thanks to an App Store submission rule [#11](https://github.com/FabrizioBrancati/BFKit-Swift/issues/11)
+- Changed `executionBlock` of `ConcurrentOperation` to pass the `concurrentOperation` variable inside the closure to be able to use the retry feature. If you don't need it simply put `_ in` after the block creation:
+ ```swift
+ let concurrentOperation = ConcurrentOperation { _ in
+ /// Your task here
+ }
+ ```
+ This also affects `SynchronousOperation`
+- Changed from Codecov to Coveralls service for code coverage
+
### Improved
+- Improved `Semaphore` with timeout handling
- Updated SwiftLint to 0.27.0
### Removed
- Removed Hound CI
+Thanks to [@zykloman](https://github.com/zykloman) and [@debjitk](https://github.com/debjitk) for this release
+
---
## [1.3.2](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.3.2) - Linux Quality
@@ -96,7 +120,7 @@ Thanks to [@BabyAzerty](https://github.com/BabyAzerty) for this release
- Updated SwiftLint to 0.21.0
### Fixed
-- Now `ConcurrentOperation` is subclassable with `open` instead of `public` Access Control [#2](https://github.com/FabrizioBrancati/Queuer/issue/2)
+- Now `ConcurrentOperation` is subclassable with `open` instead of `public` Access Control [#2](https://github.com/FabrizioBrancati/Queuer/issues/2)
- Fixed tests that sometimes fails
---
diff --git a/Package.swift b/Package.swift
index c14ec86..5cd57f1 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version:4.0
+// swift-tools-version:4.2
//
// Package.swift
// Queuer
diff --git a/Queuer.podspec b/Queuer.podspec
index 4477a21..eb86c90 100644
--- a/Queuer.podspec
+++ b/Queuer.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = 'Queuer'
s.module_name = 'Queuer'
- s.version = '1.3.2'
+ s.version = '2.0.0'
s.summary = 'Queuer is a queue manager, built on top of OperationQueue and Dispatch (aka GCD).'
s.homepage = 'https://github.com/FabrizioBrancati/Queuer'
s.screenshots = 'https://github.fabriziobrancati.com/queuer/resources/queuer-screenshot.png'
@@ -11,12 +11,12 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://github.com/FabrizioBrancati/Queuer.git', :tag => s.version }
s.documentation_url = 'https://github.fabriziobrancati.com/documentation/Queuer/'
- s.swift_version = '4.1'
+ s.swift_version = '4.2'
s.source_files = 'Sources/**/*.swift'
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.tvos.deployment_target = '9.0'
- s.watchos.deployment_target = '2.0'
+ s.watchos.deployment_target = '3.0'
end
diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj
index 618e7f1..40dce84 100644
--- a/Queuer.xcodeproj/project.pbxproj
+++ b/Queuer.xcodeproj/project.pbxproj
@@ -8,6 +8,13 @@
/* Begin PBXBuildFile section */
493F57291F21F32B009EC8FA /* Queuer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 493F57201F21F32B009EC8FA /* Queuer.framework */; };
+ 4946BDF6214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; };
+ 4946BDF7214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; };
+ 4946BDF8214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; };
+ 4946BDF9214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; };
+ 4946BDFB214D5C0100FAFC84 /* SchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */; };
+ 4946BDFC214D5C0100FAFC84 /* SchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */; };
+ 4946BDFD214D5C0100FAFC84 /* SchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */; };
4995D7431F21E19C00A34E6E /* Queuer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4995D7391F21E19B00A34E6E /* Queuer.framework */; };
4995D76F1F21ED1C00A34E6E /* Queuer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4995D7661F21ED1B00A34E6E /* Queuer.framework */; };
49B28E2C1F27EDCB00D0819A /* Queuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C7BCC11F26938F00F4FFBC /* Queuer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -15,47 +22,33 @@
49B28E2E1F27EDCC00D0819A /* Queuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C7BCC11F26938F00F4FFBC /* Queuer.h */; settings = {ATTRIBUTES = (Public, ); }; };
49C7BCCE1F26938F00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; };
49C7BCCF1F26938F00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; };
- 49C7BCD01F26938F00F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; };
49C7BCD11F26938F00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; };
49C7BCD21F26938F00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; };
- 49C7BCD31F26938F00F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; };
49C7BCD41F26938F00F4FFBC /* Queuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C7BCC11F26938F00F4FFBC /* Queuer.h */; settings = {ATTRIBUTES = (Public, ); }; };
49C7BCD51F26939900F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; };
49C7BCD61F26939900F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; };
- 49C7BCD71F26939900F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; };
49C7BCD81F26939900F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; };
49C7BCD91F26939900F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; };
- 49C7BCDA1F26939900F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; };
49C7BCDB1F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; };
49C7BCDC1F26939A00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; };
- 49C7BCDD1F26939A00F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; };
49C7BCDE1F26939A00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; };
49C7BCDF1F26939A00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; };
- 49C7BCE01F26939A00F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; };
49C7BCE11F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; };
49C7BCE21F26939A00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; };
- 49C7BCE31F26939A00F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; };
49C7BCE41F26939A00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; };
49C7BCE51F26939A00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; };
- 49C7BCE61F26939A00F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; };
49C7BCE71F26939F00F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; };
49C7BCE81F26939F00F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; };
- 49C7BCE91F26939F00F4FFBC /* RequestOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */; };
49C7BCEA1F26939F00F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; };
49C7BCEB1F26939F00F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; };
- 49C7BCEC1F26939F00F4FFBC /* URLBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */; };
49C7BCED1F2693A000F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; };
49C7BCEE1F2693A000F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; };
- 49C7BCEF1F2693A000F4FFBC /* RequestOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */; };
49C7BCF01F2693A000F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; };
49C7BCF11F2693A000F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; };
- 49C7BCF21F2693A000F4FFBC /* URLBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */; };
49C7BCF31F2693A100F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; };
49C7BCF41F2693A100F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; };
- 49C7BCF51F2693A100F4FFBC /* RequestOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */; };
49C7BCF61F2693A100F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; };
49C7BCF71F2693A100F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; };
- 49C7BCF81F2693A100F4FFBC /* URLBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -85,6 +78,8 @@
/* Begin PBXFileReference section */
493F57201F21F32B009EC8FA /* Queuer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Queuer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
493F57281F21F32B009EC8FA /* QueuerTests macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QueuerTests macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4946BDF5214D586900FAFC84 /* Scheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scheduler.swift; sourceTree = ""; };
+ 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchedulerTests.swift; sourceTree = ""; };
4995D7391F21E19B00A34E6E /* Queuer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Queuer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4995D7421F21E19C00A34E6E /* QueuerTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QueuerTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
4995D7581F21EA3F00A34E6E /* Queuer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Queuer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -93,20 +88,13 @@
49C7BCAC1F26938F00F4FFBC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentOperationTests.swift; sourceTree = ""; };
49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueuerTests.swift; sourceTree = ""; };
- 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestOperationTests.swift; sourceTree = ""; };
49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemaphoreTests.swift; sourceTree = ""; };
49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousOperationTests.swift; sourceTree = ""; };
- 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLBuilderTests.swift; sourceTree = ""; };
- 49C7BCB61F26938F00F4FFBC /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; };
- 49C7BCB71F26938F00F4FFBC /* Info-macOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; };
- 49C7BCB81F26938F00F4FFBC /* Info-tvOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; };
- 49C7BCB91F26938F00F4FFBC /* Info-watchOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-watchOS.plist"; sourceTree = ""; };
+ 49C7BCB71F26938F00F4FFBC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentOperation.swift; sourceTree = ""; };
49C7BCBC1F26938F00F4FFBC /* Queuer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queuer.swift; sourceTree = ""; };
- 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestOperation.swift; sourceTree = ""; };
49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Semaphore.swift; sourceTree = ""; };
49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousOperation.swift; sourceTree = ""; };
- 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLBuilder.swift; sourceTree = ""; };
49C7BCC11F26938F00F4FFBC /* Queuer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Queuer.h; sourceTree = ""; };
/* End PBXFileReference section */
@@ -203,10 +191,9 @@
children = (
49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */,
49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */,
- 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */,
+ 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */,
49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */,
49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */,
- 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */,
);
path = QueuerTests;
sourceTree = "";
@@ -214,10 +201,7 @@
49C7BCB51F26938F00F4FFBC /* Sources */ = {
isa = PBXGroup;
children = (
- 49C7BCB61F26938F00F4FFBC /* Info-iOS.plist */,
- 49C7BCB71F26938F00F4FFBC /* Info-macOS.plist */,
- 49C7BCB81F26938F00F4FFBC /* Info-tvOS.plist */,
- 49C7BCB91F26938F00F4FFBC /* Info-watchOS.plist */,
+ 49C7BCB71F26938F00F4FFBC /* Info.plist */,
49C7BCBA1F26938F00F4FFBC /* Queuer */,
49C7BCC11F26938F00F4FFBC /* Queuer.h */,
);
@@ -229,10 +213,9 @@
children = (
49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */,
49C7BCBC1F26938F00F4FFBC /* Queuer.swift */,
- 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */,
+ 4946BDF5214D586900FAFC84 /* Scheduler.swift */,
49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */,
49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */,
- 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */,
);
path = Queuer;
sourceTree = "";
@@ -528,12 +511,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 49C7BCE31F26939A00F4FFBC /* RequestOperation.swift in Sources */,
49C7BCE21F26939A00F4FFBC /* Queuer.swift in Sources */,
49C7BCE41F26939A00F4FFBC /* Semaphore.swift in Sources */,
49C7BCE11F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */,
+ 4946BDF7214D586900FAFC84 /* Scheduler.swift in Sources */,
49C7BCE51F26939A00F4FFBC /* SynchronousOperation.swift in Sources */,
- 49C7BCE61F26939A00F4FFBC /* URLBuilder.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -541,12 +523,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 49C7BCEF1F2693A000F4FFBC /* RequestOperationTests.swift in Sources */,
49C7BCEE1F2693A000F4FFBC /* QueuerTests.swift in Sources */,
49C7BCF01F2693A000F4FFBC /* SemaphoreTests.swift in Sources */,
+ 4946BDFC214D5C0100FAFC84 /* SchedulerTests.swift in Sources */,
49C7BCED1F2693A000F4FFBC /* ConcurrentOperationTests.swift in Sources */,
49C7BCF11F2693A000F4FFBC /* SynchronousOperationTests.swift in Sources */,
- 49C7BCF21F2693A000F4FFBC /* URLBuilderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -557,9 +538,8 @@
49C7BCCE1F26938F00F4FFBC /* ConcurrentOperation.swift in Sources */,
49C7BCD21F26938F00F4FFBC /* SynchronousOperation.swift in Sources */,
49C7BCCF1F26938F00F4FFBC /* Queuer.swift in Sources */,
- 49C7BCD31F26938F00F4FFBC /* URLBuilder.swift in Sources */,
+ 4946BDF6214D586900FAFC84 /* Scheduler.swift in Sources */,
49C7BCD11F26938F00F4FFBC /* Semaphore.swift in Sources */,
- 49C7BCD01F26938F00F4FFBC /* RequestOperation.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -567,12 +547,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 49C7BCE91F26939F00F4FFBC /* RequestOperationTests.swift in Sources */,
49C7BCE81F26939F00F4FFBC /* QueuerTests.swift in Sources */,
49C7BCEA1F26939F00F4FFBC /* SemaphoreTests.swift in Sources */,
+ 4946BDFB214D5C0100FAFC84 /* SchedulerTests.swift in Sources */,
49C7BCE71F26939F00F4FFBC /* ConcurrentOperationTests.swift in Sources */,
49C7BCEB1F26939F00F4FFBC /* SynchronousOperationTests.swift in Sources */,
- 49C7BCEC1F26939F00F4FFBC /* URLBuilderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -580,12 +559,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 49C7BCD71F26939900F4FFBC /* RequestOperation.swift in Sources */,
49C7BCD61F26939900F4FFBC /* Queuer.swift in Sources */,
49C7BCD81F26939900F4FFBC /* Semaphore.swift in Sources */,
49C7BCD51F26939900F4FFBC /* ConcurrentOperation.swift in Sources */,
+ 4946BDF9214D586900FAFC84 /* Scheduler.swift in Sources */,
49C7BCD91F26939900F4FFBC /* SynchronousOperation.swift in Sources */,
- 49C7BCDA1F26939900F4FFBC /* URLBuilder.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -593,12 +571,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 49C7BCDD1F26939A00F4FFBC /* RequestOperation.swift in Sources */,
49C7BCDC1F26939A00F4FFBC /* Queuer.swift in Sources */,
49C7BCDE1F26939A00F4FFBC /* Semaphore.swift in Sources */,
49C7BCDB1F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */,
+ 4946BDF8214D586900FAFC84 /* Scheduler.swift in Sources */,
49C7BCDF1F26939A00F4FFBC /* SynchronousOperation.swift in Sources */,
- 49C7BCE01F26939A00F4FFBC /* URLBuilder.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -606,12 +583,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 49C7BCF51F2693A100F4FFBC /* RequestOperationTests.swift in Sources */,
49C7BCF41F2693A100F4FFBC /* QueuerTests.swift in Sources */,
49C7BCF61F2693A100F4FFBC /* SemaphoreTests.swift in Sources */,
+ 4946BDFD214D5C0100FAFC84 /* SchedulerTests.swift in Sources */,
49C7BCF31F2693A100F4FFBC /* ConcurrentOperationTests.swift in Sources */,
49C7BCF71F2693A100F4FFBC /* SynchronousOperationTests.swift in Sources */,
- 49C7BCF81F2693A100F4FFBC /* URLBuilderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -647,7 +623,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-macOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
@@ -669,7 +645,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-macOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
@@ -728,6 +704,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -749,14 +726,13 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 1.3.2;
+ CURRENT_PROJECT_VERSION = 2.0.0;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
@@ -780,11 +756,11 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
+ OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=100 -Xfrontend -warn-long-function-bodies=100";
PRODUCT_NAME = Queuer;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -809,6 +785,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -830,7 +807,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 1.3.2;
+ CURRENT_PROJECT_VERSION = 2.0.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -854,10 +831,11 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=100 -Xfrontend -warn-long-function-bodies=100";
PRODUCT_NAME = Queuer;
- SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
@@ -875,7 +853,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-iOS";
@@ -895,7 +873,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-iOS";
@@ -947,7 +925,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-watchOS";
@@ -955,7 +933,7 @@
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
- WATCHOS_DEPLOYMENT_TARGET = 2.0;
+ WATCHOS_DEPLOYMENT_TARGET = 3.0;
};
name = Debug;
};
@@ -969,7 +947,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-watchOS";
@@ -977,7 +955,7 @@
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
- WATCHOS_DEPLOYMENT_TARGET = 2.0;
+ WATCHOS_DEPLOYMENT_TARGET = 3.0;
};
name = Release;
};
@@ -991,7 +969,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-tvOS";
@@ -1013,7 +991,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist";
+ INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-tvOS";
diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme
index 5a9199e..be2f8d0 100644
--- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme
+++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme
@@ -26,9 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
- shouldUseLaunchSchemeArgsEnv = "YES"
- codeCoverageEnabled = "YES">
+ codeCoverageEnabled = "YES"
+ shouldUseLaunchSchemeArgsEnv = "YES">
@@ -57,7 +56,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme
index f32be8e..394e377 100644
--- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme
+++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme
@@ -26,9 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
- shouldUseLaunchSchemeArgsEnv = "YES"
- codeCoverageEnabled = "YES">
+ codeCoverageEnabled = "YES"
+ shouldUseLaunchSchemeArgsEnv = "YES">
@@ -57,7 +56,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme
index 2cdf53b..a0fc727 100644
--- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme
+++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme
@@ -26,9 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
- shouldUseLaunchSchemeArgsEnv = "YES"
- codeCoverageEnabled = "YES">
+ codeCoverageEnabled = "YES"
+ shouldUseLaunchSchemeArgsEnv = "YES">
@@ -57,7 +56,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme
index 0624fe0..485d9c2 100644
--- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme
+++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme
@@ -26,9 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
- shouldUseLaunchSchemeArgsEnv = "YES"
- codeCoverageEnabled = "YES">
+ codeCoverageEnabled = "YES"
+ shouldUseLaunchSchemeArgsEnv = "YES">
@@ -38,7 +37,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
diff --git a/README.md b/README.md
index 2ea1cf9..4b9e05c 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[![Build Status](https://travis-ci.org/FabrizioBrancati/Queuer.svg?branch=master)](https://travis-ci.org/FabrizioBrancati/Queuer)
-[![Codecov](https://codecov.io/gh/FabrizioBrancati/Queuer/branch/master/graph/badge.svg)](https://codecov.io/gh/FabrizioBrancati/Queuer)
+[![Coverage Status](https://coveralls.io/repos/github/FabrizioBrancati/Queuer/badge.svg?branch=master)](https://coveralls.io/github/FabrizioBrancati/Queuer?branch=master)
[![Documentation](https://github.fabriziobrancati.com/documentation/Queuer/badge.svg)](https://github.fabriziobrancati.com/documentation/Queuer/)
[![codebeat badge](https://codebeat.co/badges/50844e60-f4f2-4f9f-a688-5ccc976b7c8c)](https://codebeat.co/projects/github-com-fabriziobrancati-queuer-master-9833cda0-af64-433d-a08a-cd0d50d6b579)
[![Swift Package Manager Compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)
@@ -11,8 +11,8 @@
[![Version](https://img.shields.io/cocoapods/v/Queuer.svg?style=flat)][Documentation]
[![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://github.com/FabrizioBrancati/Queuer/blob/master/LICENSE)
-[![Language](https://img.shields.io/badge/language-Swift%204.0%20%7C%204.1-orange.svg)](https://swift.org/)
-[![Platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-ffc713.svg)][Documentation]
+[![Language](https://img.shields.io/badge/language-Swift%204.2-orange.svg)](https://swift.org/)
+[![Platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-cc9c00.svg)][Documentation]
---
@@ -35,34 +35,34 @@ Features
========
Queuer is a queue manager, built on top of [OperationQueue](https://developer.apple.com/documentation/foundation/operationqueue) and [Dispatch](https://developer.apple.com/documentation/dispatch) (aka GCD).
-It allows you to create any synchronous and asynchronous task easily, with just a few lines.
+It allows you to create any asynchronous and synchronous task easily, all managed by a queue, with just a few lines.
Here is the list of all the features:
-- [x] Works on all Swift compatible platforms (even Linux `*`)
+- [x] Works on all Swift compatible platforms (even Linux)
- [x] Easy to use
- [x] Well documented (100% documented)
-- [x] Well tested (currently 99% of code coverage)
+- [x] Well tested (100% of code coverage)
- [x] Create an operation block
- [x] Create a single operation
- [x] Create chained operations
- [x] Manage a centralized queue
- [x] Create unlimited queue
- [x] Declare how many concurrent operation a queue can handle
+- [x] Create semaphores
+- [x] Create and handle schedules
+- [x] Automatically or manually retry an operation
- [ ] Ability to restore uncompleted operations
-- [ ] Wrappers for other frameworks (like Alamofire, Moya, ecc) maybe with pod subspecs
-
-> `*` Currently, `URLSession.shared` property is not yet implemented on Linux.
+- [ ] Throlling between each automatic operation retry
Requirements
============
-| **Swift** | **Xcode** | **Queuer** | **iOS** | **macOS** | **tvOS** | **watchOS** | **Linux** |
-|-----------|-----------|---------------|---------|-----------|----------|-------------|-----------|
-| 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` |
-| 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` |
-| 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` |
-
-> `*` Currently, `URLSession.shared` property is not yet implemented on Linux.
+| **Swift** | **Xcode** | **Queuer** | **iOS** | **macOS** | **tvOS** | **watchOS** | **Linux** |
+|-----------|-----------|---------------|---------|------------|-----------|-------------|-----------|
+| 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] |
+| 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] |
+| 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] |
+| 4.2 | 10.0 | 2.0.0 | 8.0+ | 10.10+ | 9.0+ | 3.0+ | ![✓] |
Installing
==========
@@ -131,7 +131,7 @@ See [Requirements](https://github.com/FabrizioBrancati/Queuer#requirements) sect
- Create a **Package.swift** file in your **project directory** and write into:
```swift
- // swift-tools-version:4.0
+ // swift-tools-version:4.2
import PackageDescription
let package = Package(
@@ -155,6 +155,18 @@ See [Requirements](https://github.com/FabrizioBrancati/Queuer#requirements) sect
Usage
=====
+- [Shared Queuer](https://github.com/FabrizioBrancati/Queuer#shared-queuer)
+- [Custom Queue](https://github.com/FabrizioBrancati/Queuer#custom-queue)
+- [Create an Operation Block](https://github.com/FabrizioBrancati/Queuer#create-an-operation-block)
+- [Chained Operations](https://github.com/FabrizioBrancati/Queuer#chained-operations)
+- [Queue States](https://github.com/FabrizioBrancati/Queuer#queue-states)
+- [Asynchronous Operation](https://github.com/FabrizioBrancati/Queuer#anynchronous-operation)
+- [Synchronous Operation](https://github.com/FabrizioBrancati/Queuer#synchronous-operation)
+- [Automatically Retry an Operation](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation)
+- [Manually Retry an Operation](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation)
+- [Scheduler](https://github.com/FabrizioBrancati/Queuer#scheduler)
+- [Semaphore](https://github.com/FabrizioBrancati/Queuer#semaphore)
+
### Shared Queuer
```swift
@@ -184,7 +196,7 @@ You have three methods to add an `Operation` block:
- Creating a `ConcurrentOperation` with a block:
```swift
- let concurrentOperation = ConcurrentOperation {
+ let concurrentOperation = ConcurrentOperation { _ in
/// Your task here
}
queue.addOperation(concurrentOperation)
@@ -192,7 +204,7 @@ You have three methods to add an `Operation` block:
- Creating a `SynchronousOperation` with a block:
```swift
- let synchronousOperation = SynchronousOperation {
+ let synchronousOperation = SynchronousOperation { _ in
/// Your task here
}
queue.addOperation(concurrentOperation)
@@ -204,10 +216,10 @@ You have three methods to add an `Operation` block:
Chained Operations are operations that add a dependency each other.
They follow the given array order, for example: `[A, B, C] = A -> B -> C -> completionBlock`.
```swift
-let concurrentOperation1 = ConcurrentOperation {
+let concurrentOperation1 = ConcurrentOperation { _ in
/// Your task 1 here
}
-let concurrentOperation2 = ConcurrentOperation {
+let concurrentOperation2 = ConcurrentOperation { _ in
/// Your task 2 here
}
queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
@@ -225,13 +237,13 @@ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
queue.pause()
```
> By calling `pause()` you will not be sure that every operation will be paused.
- If the Operation is already started it will not be on pause until it's a custom Operation that overrides `pause()` function or is a `RequestOperation`.
+ If the Operation is already started it will not be on pause until it's a custom Operation that overrides `pause()` function.
- Resume queue:
```swift
queue.resume()
```
- > To have a complete `pause` and `resume` states you must create a custom Operation that overrides `pause()` and `resume()` function or use a `RequestOperation`.
+ > To have a complete `pause` and `resume` states you must create a custom Operation that overrides `pause()` and `resume()` function.
- Wait until all operations are finished:
```swift
@@ -244,12 +256,11 @@ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
It allows synchronous and asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block.
You can create your custom `ConcurrentOperation` by subclassing it.
-You must override `execute()` function and call the `finish()` function inside it, when the task has finished its job to notify the queue.
-Look at [RequestOperation.swift](https://github.com/FabrizioBrancati/Queuer/blob/master/Sources/Queuer/RequestOperation.swift) if you are looking for an example.
+You must override `execute()` function and call the `finish()` function inside it, when the task has finished its job to notify the queue.
For convenience it has an `init` function with a completion block:
```swift
-let concurrentOperation = ConcurrentOperation {
+let concurrentOperation = ConcurrentOperation { _ in
/// Your task here
}
concurrentOperation.addToQueue(queue)
@@ -266,12 +277,68 @@ There are three methods to create synchronous tasks or even queue:
For convenience it has an `init` function with a completion block:
```swift
-let synchronousOperation = SynchronousOperation {
+let synchronousOperation = SynchronousOperation { _ in
/// Your task here
}
synchronousOperation.addToQueue(queue)
```
+### Automatically Retry an Operation
+An `Operation` is passed to every closure, with it you can set and handle the retry feature.
+By default the retry feature is disabled, to enable it simply set the `hasFailed` property to `true`. With `hasFailed` to `true` the `Operation` will retry until reaches `maximumRetries` property value. To let the `Operation` know when everything is ok, you must set `hasFailed` to `false`.
+With `currentAttempt` you can know at which attempt the `Operation` is.
+```swift
+let concurrentOperation = ConcurrentOperation { operation in
+ /// Your task here
+ if /* Failing */ {
+ operation.hasFailed = true
+ } else {
+ operation.hasFailed = false
+ }
+}
+```
+
+### Manually Retry an Operation
+It's even possible to manually retry an `Operation` when you think that the execution will be successful.
+An `Operation` is passed to every closure, with it you can set and handle the retry feature.
+By default the manual retry feature is disabled, to enable it simply set the `manualRetry` property to `true`, you must do this outside of the execution closure. You must also set `hasFailed` to `true` or `false` to let the `Operation` when is everything ok, like the automatic retry feature.
+To let the `Operation` retry your execution closure, you have to call the `retry()` function. If the `retry()` is not called, you may block the entire queue. Be sure to call it at least `maximumRetries` times, it is not a problem if you call `retry()` more times than is needed, your execution closure will not be executed more times than the `maximumRetries` value.
+```swift
+let concurrentOperation = ConcurrentOperation { operation in
+ /// Your task here
+ if /* Failing */ {
+ operation.hasFailed = true
+ } else {
+ operation.hasFailed = false
+ }
+}
+concurrentOperation.manualRetry = true
+/// Later on your code
+concurrentOperation.retry()
+```
+
+### Scheduler
+A `Scheduler` is a struct that uses the GDC's `DispatchSourceTimer` to create a timer that can execute functions with a specified interval and quality of service.
+
+```swift
+let schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) {
+ /// Your task here
+}
+```
+
+You can even create a `Scheduler` without the handler and set it later:
+```swift
+var schedule = Scheduler(deadline: .now(), repeating: .seconds(1))
+schedule.setHandler {
+ /// Your task here.
+}
+```
+
+With `timer` property you can access to all `DispatchSourceTimer` properties and functions, like `cancel()`:
+```swift
+schedule.timer.cancel()
+```
+
### Semaphore
A `Semaphore` is a struct that uses the GCD's `DispatchSemaphore` to create a semaphore on the function and wait until it finish its job.
I recommend you to use a `defer { semaphore.continue() }` right after the `Semaphore` creation and `wait()` call.
@@ -283,6 +350,11 @@ defer { semaphore.continue() }
/// Your task here
```
+You can even set a custom timeout, default is `.distantFuture`:
+```swift
+semaphore.wait(DispatchTime(uptimeNanoseconds: 1_000_000_000))
+```
+
It's more useful if used inside an asynchronous task:
```swift
let concurrentOperation = ConcurrentOperation {
@@ -293,40 +365,6 @@ concurrentOperation.addToQueue(queue)
semaphore.wait()
```
-### Request Operation `*`
-`RequestOperation` allows you to easily create a network request and add it to a queue:
-```swift
-let requestOperation: RequestOperation = RequestOperation(url: self.testAddress) { success, response, data, error in
-
-}
-requestOperation.addToQueue(queue)
-```
-Allowed parameters in `RequestOperation` `init` function:
-- `url` is a `String` representing the request URL
-- `query` is `Dictionary` representing the request query parameters to be added to the `url` with `?` and `&` characters
-- `timeout` is the request timeout
-- `method` is the request method, you can choose to one of: `connect`, `delete`, `get`, `head`, `options`, `patch`, `post` and `put`
-- `cachePolicy` is the request cache policy, referrer to [CachePolicy documentation](https://developer.apple.com/documentation/foundation/nsurlrequest.cachepolicy)
-- `headers` is a `Dictionary` representing the request headers
-- `body` is a `Data` representing the request body
-- `completionHandler` is the request response handler
-
-Response handler variables:
-- `success` is a `Bool` indicating if the request was successful.
- It's successful if its status is between 200 and 399, it wasn't cancelled and did't get any other network error.
-- `respose` is an `HTTPURLResponse` instance.
- It contains all the response headers and the status code.
- May be `nil`.
-- `data` is a `Data` instance with the request body.
- You must convert, to a JSON or String in example, it in order to use.
- May be `nil`.
-- `error` is an `Error` instance with the request error.
- May be `nil`.
-
-It can be `pause`d, `resume`d, `cancel`led and chained with other `Operation`s.
-
-> `*` Currently, `URLSession.shared` property is not yet implemented on Linux, also `RequestOperation` is currently deprecated and will be removed in Queuer 2.
-
Documentation
=============
diff --git a/Sources/Info-iOS.plist b/Sources/Info-iOS.plist
deleted file mode 100644
index 2a3d8ce..0000000
--- a/Sources/Info-iOS.plist
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.3.2
- CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
- NSPrincipalClass
-
-
-
diff --git a/Sources/Info-tvOS.plist b/Sources/Info-tvOS.plist
deleted file mode 100644
index 0fb03af..0000000
--- a/Sources/Info-tvOS.plist
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.3.2
- CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
- NSPrincipalClass
-
- UIRequiredDeviceCapabilities
-
- arm64
-
-
-
diff --git a/Sources/Info-watchOS.plist b/Sources/Info-watchOS.plist
deleted file mode 100644
index 2a3d8ce..0000000
--- a/Sources/Info-watchOS.plist
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.3.2
- CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
- NSPrincipalClass
-
-
-
diff --git a/Sources/Info-macOS.plist b/Sources/Info.plist
similarity index 88%
rename from Sources/Info-macOS.plist
rename to Sources/Info.plist
index 0d1adf9..73dbae2 100644
--- a/Sources/Info-macOS.plist
+++ b/Sources/Info.plist
@@ -15,12 +15,16 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 1.3.2
+ 2.0.0
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSHumanReadableCopyright
Copyright © 2017 - 2018 Fabrizio Brancati.
NSPrincipalClass
+ UIRequiredDeviceCapabilities
+
+ arm64
+
diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift
index 2906a98..db1cc2f 100644
--- a/Sources/Queuer/ConcurrentOperation.swift
+++ b/Sources/Queuer/ConcurrentOperation.swift
@@ -26,26 +26,18 @@
import Foundation
-/// It allows asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block.
+/// It allows asynchronous tasks, has a pause and resume states,
+/// can be easily added to a queue and can be created with a block.
open class ConcurrentOperation: Operation {
- /// Operation's execution block.
- public var executionBlock: (() -> Void)?
+ /// `Operation`'s execution block.
+ public var executionBlock: ((_ operation: ConcurrentOperation) -> Void)?
- /// Creates the Operation with an execution block.
- ///
- /// - Parameter executionBlock: Execution block.
- public init(executionBlock: (() -> Void)? = nil) {
- super.init()
-
- self.executionBlock = executionBlock
- }
-
- /// Set the Operation as asynchronous.
+ /// Set the `Operation` as asynchronous.
override open var isAsynchronous: Bool {
return true
}
- /// Set if the Operation is executing.
+ /// Set if the `Operation` is executing.
private var _executing = false {
willSet {
willChangeValue(forKey: "isExecuting")
@@ -55,12 +47,12 @@ open class ConcurrentOperation: Operation {
}
}
- /// Set if the Operation is executing.
+ /// Set if the `Operation` is executing.
override open var isExecuting: Bool {
return _executing
}
- /// Set if the Operation is finished.
+ /// Set if the `Operation` is finished.
private var _finished = false {
willSet {
willChangeValue(forKey: "isFinished")
@@ -70,49 +62,102 @@ open class ConcurrentOperation: Operation {
}
}
- /// Set if the Operation is finished.
+ /// Set if the `Operation` is finished.
override open var isFinished: Bool {
return _finished
}
- /// Start the Operation.
+ /// You should use `hasFailed` if you want the retry feature.
+ /// Set it to `true` if the `Operation` has failed, otherwise `false`.
+ /// Default is `false` to avoid retries.
+ open var hasFailed = false
+
+ /// Maximum allowed retries.
+ /// Default are 3 retries.
+ open var maximumRetries = 3
+
+ /// Current retry attempt.
+ open private(set) var currentAttempt = 1
+
+ /// Allows for manual retries.
+ /// If set to `true`, `retry()` function must be manually called.
+ /// Default is `false` to automatically retry.
+ open var manualRetry = false
+
+ /// Specify if the `Operation` should retry another time.
+ private var shouldRetry = true
+
+ /// Creates the `Operation` with an execution block.
+ ///
+ /// - Parameter executionBlock: Execution block.
+ public init(executionBlock: ((_ operation: ConcurrentOperation) -> Void)? = nil) {
+ super.init()
+
+ self.executionBlock = executionBlock
+ }
+
+ /// Start the `Operation`.
override open func start() {
_executing = true
execute()
}
- /// Execute the Operation.
+ /// Retry function.
+ /// It only works if `manualRetry` property has been set to `true`.
+ open func retry() {
+ if manualRetry, shouldRetry, let executionBlock = executionBlock {
+ executionBlock(self)
+ finish(hasFailed)
+ }
+ }
+
+ /// Execute the `Operation`.
/// If `executionBlock` is set, it will be executed and also `finish()` will be called.
open func execute() {
if let executionBlock = executionBlock {
- executionBlock()
- self.finish()
+ while shouldRetry, !manualRetry {
+ executionBlock(self)
+ finish(hasFailed)
+ }
+
+ retry()
}
}
- /// Notify the completion of async task and hence the completion of the operation.
- /// Must be called when the Operation is finished.
- open func finish() {
- _executing = false
- _finished = true
+ /// Notify the completion of async task and hence the completion of the `Operation`.
+ /// Must be called when the `Operation` is finished.
+ ///
+ /// - Parameter hasFailed: Set it to `true` if the `Operation` has failed, otherwise `false`.
+ open func finish(_ hasFailed: Bool) {
+ if !hasFailed || currentAttempt >= maximumRetries {
+ _executing = false
+ _finished = true
+ shouldRetry = false
+ } else {
+ currentAttempt += 1
+ shouldRetry = true
+ }
}
- /// Pause the current Operation, if it's supported.
+ /// Pause the current `Operation`, if it's supported.
/// Must be overridend by subclass to get a custom pause action.
open func pause() {}
- /// Resume the current Operation, if it's supported.
+ /// Resume the current `Operation`, if it's supported.
/// Must be overridend by subclass to get a custom resume action.
open func resume() {}
-
- /// Adds the Operation to `shared` Queuer.
+}
+
+/// `ConcurrentOperation` extension with queue handling.
+public extension ConcurrentOperation {
+ /// Adds the `Operation` to `shared` Queuer.
public func addToSharedQueuer() {
Queuer.shared.addOperation(self)
}
- /// Adds the Operation to the custom queue.
+ /// Adds the `Operation` to the custom queue.
///
- /// - Parameter queue: Custom queue where the Operation will be added.
+ /// - Parameter queue: Custom queue where the `Operation` will be added.
public func addToQueue(_ queue: Queuer) {
queue.addOperation(self)
}
diff --git a/Sources/Queuer/Queuer.swift b/Sources/Queuer/Queuer.swift
index 49796bc..0f4d151 100644
--- a/Sources/Queuer/Queuer.swift
+++ b/Sources/Queuer/Queuer.swift
@@ -31,20 +31,20 @@ public class Queuer {
/// Shared Queuer.
public static let shared = Queuer(name: "Queuer")
- /// Queuer OperationQueue.
+ /// Queuer `OperationQueue`.
public let queue = OperationQueue()
- /// Total Operation count in queue.
+ /// Total `Operation` count in queue.
public var operationCount: Int {
return queue.operationCount
}
- /// Operations currently in queue.
+ /// `Operation`s currently in queue.
public var operations: [Operation] {
return queue.operations
}
- /// The default service level to apply to operations executed using the queue.
+ /// The default service level to apply to `Operation`s executed using the queue.
public var qualityOfService: QualityOfService {
get {
return queue.qualityOfService
@@ -61,7 +61,7 @@ public class Queuer {
return !queue.isSuspended
}
- /// Define the max concurrent operation count.
+ /// Define the max concurrent `Operation`s count.
public var maxConcurrentOperationCount: Int {
get {
return queue.maxConcurrentOperationCount
@@ -75,37 +75,69 @@ public class Queuer {
///
/// - Parameters:
/// - name: Custom queue name.
- /// - maxConcurrentOperationCount: The max concurrent operation count.
- /// - qualityOfService: The default service level to apply to operations executed using the queue.
+ /// - maxConcurrentOperationCount: The max concurrent `Operation`s count.
+ /// - qualityOfService: The default service level to apply to `Operation`s executed using the queue.
public init(name: String, maxConcurrentOperationCount: Int = Int.max, qualityOfService: QualityOfService = .default) {
queue.name = name
self.maxConcurrentOperationCount = maxConcurrentOperationCount
self.qualityOfService = qualityOfService
}
- /// Add an Operation to be executed asynchronously.
+ /// Cancel all `Operation`s in queue.
+ public func cancelAll() {
+ queue.cancelAllOperations()
+ }
+
+ /// Pause the queue.
+ public func pause() {
+ queue.isSuspended = true
+
+ for operation in queue.operations where operation is ConcurrentOperation {
+ (operation as? ConcurrentOperation)?.pause()
+ }
+ }
+
+ /// Resume the queue.
+ public func resume() {
+ queue.isSuspended = false
+
+ for operation in queue.operations where operation is ConcurrentOperation {
+ (operation as? ConcurrentOperation)?.resume()
+ }
+ }
+
+ /// Blocks the current thread until all of the receiver’s queued and executing
+ /// `Operation`s finish executing.
+ public func waitUntilAllOperationsAreFinished() {
+ queue.waitUntilAllOperationsAreFinished()
+ }
+}
+
+/// `Queuer` extension with `Operation`s handling.
+public extension Queuer {
+ /// Add an `Operation` to be executed asynchronously.
///
/// - Parameter block: Block to be executed.
public func addOperation(_ operation: @escaping () -> Void) {
queue.addOperation(operation)
}
- /// Add an Operation to be executed asynchronously.
+ /// Add an `Operation` to be executed asynchronously.
///
- /// - Parameter operation: Operation to be executed.
+ /// - Parameter operation: `Operation` to be executed.
public func addOperation(_ operation: Operation) {
queue.addOperation(operation)
}
- /// Add an Array of chained Operations.
+ /// Add an Array of chained `Operation`s.
///
/// Example:
///
/// [A, B, C] = A -> B -> C -> completionHandler.
///
/// - Parameters:
- /// - operations: Operations Array.
- /// - completionHandler: Completion block to be exectuted when all Operations
+ /// - operations: `Operation`s Array.
+ /// - completionHandler: Completion block to be exectuted when all `Operation`s
/// are finished.
public func addChainedOperations(_ operations: [Operation], completionHandler: (() -> Void)? = nil) {
for (index, operation) in operations.enumerated() {
@@ -120,53 +152,31 @@ public class Queuer {
return
}
- let completionOperation = BlockOperation(block: completionHandler)
- if !operations.isEmpty {
- completionOperation.addDependency(operations[operations.count - 1])
- }
- addOperation(completionOperation)
+ addCompletionHandler(completionHandler)
}
- /// Add an Array of chained Operations.
+ /// Add an Array of chained `Operation`s.
///
/// Example:
///
/// [A, B, C] = A -> B -> C -> completionHandler.
///
/// - Parameters:
- /// - operations: Operations list.
- /// - completionHandler: Completion block to be exectuted when all Operations
+ /// - operations: `Operation`s list.
+ /// - completionHandler: Completion block to be exectuted when all `Operation`s
/// are finished.
public func addChainedOperations(_ operations: Operation..., completionHandler: (() -> Void)? = nil) {
addChainedOperations(operations, completionHandler: completionHandler)
}
- /// Cancel all Operations in queue.
- public func cancelAll() {
- queue.cancelAllOperations()
- }
-
- /// Pause the queue.
- public func pause() {
- queue.isSuspended = true
-
- for operation in queue.operations where operation is ConcurrentOperation {
- (operation as? ConcurrentOperation)?.pause()
- }
- }
-
- /// Resume the queue.
- public func resume() {
- queue.isSuspended = false
-
- for operation in queue.operations where operation is ConcurrentOperation {
- (operation as? ConcurrentOperation)?.resume()
+ /// Add a completion block to the queue.
+ ///
+ /// - Parameter completionHandler: Completion handler to be executed as last `Operation`.
+ public func addCompletionHandler(_ completionHandler: @escaping () -> Void) {
+ let completionOperation = BlockOperation(block: completionHandler)
+ if let lastOperation = operations.last {
+ completionOperation.addDependency(lastOperation)
}
- }
-
- /// Blocks the current thread until all of the receiver’s queued and executing
- /// operations finish executing.
- public func waitUntilAllOperationsAreFinished() {
- queue.waitUntilAllOperationsAreFinished()
+ addOperation(completionOperation)
}
}
diff --git a/Sources/Queuer/RequestOperation.swift b/Sources/Queuer/RequestOperation.swift
deleted file mode 100644
index 3fc7c40..0000000
--- a/Sources/Queuer/RequestOperation.swift
+++ /dev/null
@@ -1,230 +0,0 @@
-//
-// RequestOperation.swift
-// Queuer
-//
-// MIT License
-//
-// Copyright (c) 2017 - 2018 Fabrizio Brancati
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-#if !os(Linux)
-
-import Foundation
-
-/// HTTP Method enum.
-public enum HTTPMethod: String {
- /// CONNECT method.
- case connect = "CONNECT"
- /// DELETE method.
- case delete = "DELETE"
- /// GET method.
- case get = "GET"
- /// HEAD method.
- case head = "HEAD"
- /// OPTIONS method.
- case options = "OPTIONS"
- /// PATCH method.
- case patch = "PATCH"
- /// POST method.
- case post = "POST"
- /// PUT method.
- case put = "PUT"
-}
-
-/// RequestOperation helps you to create network operation with an easy interface.
-@available(*, deprecated: 1.3.2, message: "`RequestOperation` is deprecated and will be removed in Queuer 2.")
-open class RequestOperation: ConcurrentOperation {
- /// Custom HTTP errors.
- public enum RequestError: Error {
- /// URL doesn't exist.
- case urlError
- /// Operation has been cancelled.
- case operationCancelled
- }
-
- /// Request closure alias.
- public typealias RequestClosure = (Bool, HTTPURLResponse?, Data?, Error?) -> Void
-
- /// Global cache policy for all request.
- /// Also cache policy can be set per request.
- public static var globalCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy
-
- /// Request task.
- public private(set) var task: URLSessionDataTask?
- /// Request URL.
- public private(set) var url: URL?
- /// Request query.
- public private(set) var query: String?
- /// Request complete URL
- public private(set) var completeURL: URL?
- /// Request timeout.
- public private(set) var timeout: TimeInterval = 30
- /// Request HTTP method.
- public private(set) var method: HTTPMethod = .get
- /// Request cache policy.
- public private(set) var cachePolicy: URLRequest.CachePolicy = globalCachePolicy
- /// Request headers.
- public private(set) var headers: [String: String]?
- /// Request body.
- public private(set) var body: Data?
- /// Request completionHandler.
- public private(set) var completionHandler: RequestClosure?
-
- /// URLSession instance.
- open var session: URLSession {
- let configuration = URLSessionConfiguration.default
- if #available(iOS 11, macOS 10.13, tvOS 11, watchOS 4, *) {
- configuration.waitsForConnectivity = true
- }
- return URLSession(configuration: configuration)
- }
-
- /// URLRequest instance.
- private var request: URLRequest! // swiftlint:disable:this implicitly_unwrapped_optional
-
- /// Private init with executrion block.
- /// You can't create a RequestOperation with only an execution block.
- ///
- /// - Parameter block: Execution block.
- override internal init(executionBlock: (() -> Void)? = nil) {
- super.init(executionBlock: nil)
- }
-
- /// Creates a RequestOperation, ready to be added in a queue.
- ///
- /// - Parameters:
- /// - url: Request URL String.
- /// - query: Request query. Default is nil.
- /// - timeout: Request timeout. Default is 30 seconds.
- /// - method: Request HTTP method. Default is `.get`.
- /// - cachePolicy: Request cache policy. Use static var `globalCachePolicy`
- /// to set a global cache policy for all the RequestOperations.
- /// - headers: Request headers. Defatult is nil.
- /// - body: Request body. Default is nil.
- /// - completionHandler: Request completion handler. Default is nil.
- public init(url: String, query: [String: String]? = nil, timeout: TimeInterval = 30, method: HTTPMethod = .get, cachePolicy: URLRequest.CachePolicy = globalCachePolicy, headers: [String: String]? = nil, body: Data? = nil, completionHandler: RequestClosure? = nil) {
- super.init()
-
- let query = URLBuilder.build(query: query)
-
- self.query = query
- self.url = URL(string: url)
- self.completeURL = URL(string: url + query)
- self.timeout = timeout
- self.method = method
- self.cachePolicy = cachePolicy
- self.headers = headers
- self.body = body
- self.completionHandler = completionHandler
- }
-
- /// Executes the request operation asynchronously.
- override open func execute() {
- /// Check if the Operation has been cancelled.
- guard !self.isCancelled else {
- if let completionHandler = completionHandler {
- completionHandler(false, nil, nil, RequestError.operationCancelled)
- }
-
- /// Notify that the Operation has finished execution.
- self.finish()
-
- return
- }
-
- /// Check if the URL can be used.
- guard let url = self.completeURL else {
- if let completionHandler = completionHandler {
- completionHandler(false, nil, nil, RequestError.urlError)
- }
-
- /// Notify that the Operation has finished execution.
- finish()
-
- return
- }
-
- /// Creates the request.
- request = URLRequest(url: url, cachePolicy: self.cachePolicy, timeoutInterval: self.timeout)
- /// Set the HTTP method.
- request.httpMethod = method.rawValue
- /// Set the HTTP body.
- if let body = body {
- request.httpBody = body
- }
- /// Set all the HTTP headers.
- if let headers = headers {
- headers.forEach { request.addValue($1, forHTTPHeaderField: $0) }
- }
-
- /// Create the task.
- task = session.dataTask(with: request) { [weak self] data, response, error in
- /// Check if the Operation has a completion handler, has an HTTP response
- /// and has not been canceled.
- if let strongSelf = self {
- if let completionHandler = strongSelf.completionHandler {
- if let httpResponse = response as? HTTPURLResponse {
- var error: Error? = error
- /// Set `success` to true if the HTTP status code
- /// is greater or equal than 200 and less than 400
- /// and has not been cancelled.
- let success: Bool = httpResponse.statusCode >= 200 && httpResponse.statusCode < 400 && !strongSelf.isCancelled
-
- /// Check again if the request has not been cancelled.
- if strongSelf.isCancelled {
- error = RequestError.operationCancelled
- }
-
- completionHandler(success, httpResponse, data, error)
- } else {
- completionHandler(false, nil, data, error)
- }
- }
- /// Notify that the Operation has finished execution.
- strongSelf.finish()
- }
- }
- /// Start the task.
- task?.resume()
- }
-
- /// Cancels the request operation.
- override open func cancel() {
- super.cancel()
-
- task?.cancel()
- }
-
- /// Suspends the request operation.
- override open func pause() {
- super.pause()
-
- task?.suspend()
- }
-
- /// Resumes the request operation.
- override open func resume() {
- super.resume()
-
- task?.resume()
- }
-}
-
-#endif
diff --git a/Sources/Queuer/Scheduler.swift b/Sources/Queuer/Scheduler.swift
new file mode 100644
index 0000000..12014e0
--- /dev/null
+++ b/Sources/Queuer/Scheduler.swift
@@ -0,0 +1,77 @@
+//
+// Scheduler.swift
+// Queuer
+//
+// MIT License
+//
+// Copyright (c) 2017 - 2018 Fabrizio Brancati
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+import Dispatch
+import Foundation
+
+/// Scheduler struct, based on top of `DispatchSourceTimer`.
+public struct Scheduler {
+ /// Schedule timer.
+ public private(set) var timer: DispatchSourceTimer
+ /// Schedule deadline.
+ public private(set) var deadline: DispatchTime
+ /// Schedule repeating interval.
+ public private(set) var repeating: DispatchTimeInterval
+ /// Schedule quality of service.
+ public private(set) var qualityOfService: DispatchQoS
+ /// Schedule handler.
+ public private(set) var handler: (() -> Void)?
+
+ /// Create a schedule.
+ ///
+ /// - Parameters:
+ /// - deadline: Deadline.
+ /// - repeating: Repeating interval
+ /// - qualityOfService: Quality of service.
+ /// - handler: Closure handler.
+ public init(deadline: DispatchTime, repeating: DispatchTimeInterval, qualityOfService: DispatchQoS = .default, handler: (() -> Void)? = nil) {
+ self.deadline = deadline
+ self.repeating = repeating
+ self.qualityOfService = qualityOfService
+ self.handler = handler
+
+ timer = DispatchSource.makeTimerSource()
+ timer.schedule(deadline: deadline, repeating: repeating)
+ if let handler = handler {
+ timer.setEventHandler(qos: qualityOfService) {
+ handler()
+ }
+ timer.resume()
+ }
+ }
+
+ /// Set the handler after schedule creation.
+ ///
+ /// - Parameter handler: Closure handler.
+ public mutating func setHandler(_ handler: @escaping () -> Void) {
+ self.handler = handler
+
+ timer.setEventHandler(qos: qualityOfService) {
+ handler()
+ }
+ timer.resume()
+ }
+}
diff --git a/Sources/Queuer/Semaphore.swift b/Sources/Queuer/Semaphore.swift
index a31987c..cc9fe31 100644
--- a/Sources/Queuer/Semaphore.swift
+++ b/Sources/Queuer/Semaphore.swift
@@ -27,9 +27,9 @@
import Dispatch
import Foundation
-/// DispatchSemaphore struct wrapper.
+/// `DispatchSemaphore` struct wrapper.
public struct Semaphore {
- /// Private DispatchSemaphore.
+ /// Private `DispatchSemaphore`.
private let semaphore: DispatchSemaphore
/// Creates new counting semaphore with an initial value.
@@ -39,15 +39,18 @@ public struct Semaphore {
/// to the value.
///
/// - Parameter poolSize: The starting value for the semaphore.
- /// Passing a value less than zero will cause NULL to be returned.
+ /// Passing a value less than zero will cause `NULL` to be returned.
public init(poolSize: Int = 0) {
semaphore = DispatchSemaphore(value: poolSize)
}
/// Wait for a `continue` function call.
+ ///
+ /// - Parameter timeout: The timeout `DispatchTime`, default is `.distantFuture`.
+ /// - Returns: Returns a `DispatchTimeoutResult`.
@discardableResult
- public func wait() -> DispatchTimeoutResult {
- return semaphore.wait(timeout: .distantFuture)
+ public func wait(_ timeout: DispatchTime = .distantFuture) -> DispatchTimeoutResult {
+ return semaphore.wait(timeout: timeout)
}
/// This function returns non-zero if a thread is woken. Otherwise, zero is returned.
diff --git a/Sources/Queuer/SynchronousOperation.swift b/Sources/Queuer/SynchronousOperation.swift
index db89b70..6f51c82 100644
--- a/Sources/Queuer/SynchronousOperation.swift
+++ b/Sources/Queuer/SynchronousOperation.swift
@@ -28,28 +28,32 @@ import Foundation
/// It allows synchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block.
public class SynchronousOperation: ConcurrentOperation {
- /// Private semaphore instance.
+ /// Private `Semaphore` instance.
private let semaphore = Semaphore()
- /// Set the Operation as synchronous.
+ /// Set the `Operation` as synchronous.
override public var isAsynchronous: Bool {
return false
}
- /// Notify the completion of sync task and hence the completion of the operation.
- /// Must be called when the Operation is finished.
- override public func finish() {
+ /// Notify the completion of async task and hence the completion of the `Operation`.
+ /// Must be called when the `Operation` is finished.
+ ///
+ /// - Parameter hasFailed: Set it to `true` if the `Operation` has failed, otherwise `false`.
+ override public func finish(_ hasFailed: Bool) {
+ super.finish(hasFailed)
+
semaphore.continue()
}
- /// Advises the operation object that it should stop executing its task.
+ /// Advises the `Operation` object that it should stop executing its task.
override public func cancel() {
super.cancel()
semaphore.continue()
}
- /// Execute the Operation.
+ /// Execute the `Operation`.
/// If `executionBlock` is set, it will be executed and also `finish()` will be called.
override public func execute() {
super.execute()
diff --git a/Tests/Info.plist b/Tests/Info.plist
index df52bb5..60e89d2 100644
--- a/Tests/Info.plist
+++ b/Tests/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.3.2
+ 2.0.0
CFBundleVersion
1
diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift
index fd29c7b..23b901b 100644
--- a/Tests/LinuxMain.swift
+++ b/Tests/LinuxMain.swift
@@ -23,16 +23,24 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
+//
+//
+//
+// NOTE: This file was generated by generate_linux_tests.rb
+//
+// Do NOT edit this file directly as it will be regenerated automatically when needed.
+//
-#if os(Linux)
-@testable import QueuerTests
import XCTest
-XCTMain([
- testCase(ConcurrentOperationTests.allTests),
- testCase(QueuerTests.allTests),
- testCase(URLBuilderTests.allTests),
- testCase(SemaphoreTests.allTests),
- testCase(SynchronousOperationTests.allTests)
-])
+#if os(Linux) || os(FreeBSD)
+ @testable import QueuerTests
+
+ XCTMain([
+ testCase(ConcurrentOperationTests.allTests),
+ testCase(QueuerTests.allTests),
+ testCase(SchedulerTests.allTests),
+ testCase(SemaphoreTests.allTests),
+ testCase(SynchronousOperationTests.allTests)
+ ])
#endif
diff --git a/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift
new file mode 100644
index 0000000..b4025d9
--- /dev/null
+++ b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift
@@ -0,0 +1,50 @@
+//
+// ConcurrentOperationTests+XCTest.swift
+// Queuer
+//
+// MIT License
+//
+// Copyright (c) 2017 - 2018 Fabrizio Brancati
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//
+//
+// NOTE: This file was generated by generate_linux_tests.rb
+//
+// Do NOT edit this file directly as it will be regenerated automatically when needed.
+//
+
+import XCTest
+
+internal extension ConcurrentOperationTests {
+ internal static var allTests: [(String, (ConcurrentOperationTests) -> () throws -> Void)] {
+ return [
+ ("testInitWithExecutionBlock", testInitWithExecutionBlock),
+ ("testIsAsynchronous", testIsAsynchronous),
+ ("testAddToSharedQueuer", testAddToSharedQueuer),
+ ("testAddToQueue", testAddToQueue),
+ ("testSimpleRetry", testSimpleRetry),
+ ("testChainedRetry", testChainedRetry),
+ ("testCanceledChainedRetry", testCanceledChainedRetry),
+ ("testChainedManualRetry", testChainedManualRetry),
+ ("testChainedWrongManualRetry", testChainedWrongManualRetry)
+ ]
+ }
+}
diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift
index 90a6a74..5ea45d9 100644
--- a/Tests/QueuerTests/ConcurrentOperationTests.swift
+++ b/Tests/QueuerTests/ConcurrentOperationTests.swift
@@ -28,19 +28,12 @@
import XCTest
internal class ConcurrentOperationTests: XCTestCase {
- internal static let allTests = [
- ("testInitWithExecutionBlock", testInitWithExecutionBlock),
- ("testIsAsynchronous", testIsAsynchronous),
- ("testAddToSharedQueuer", testAddToSharedQueuer),
- ("testAddToQueue", testAddToQueue)
- ]
-
internal func testInitWithExecutionBlock() {
let queue = Queuer(name: "ConcurrentOperationTestInitWithExecutionBlock")
let testExpectation = expectation(description: "Init With Execution Block")
- let concurrentOperation = ConcurrentOperation {
+ let concurrentOperation = ConcurrentOperation { _ in
testExpectation.fulfill()
}
concurrentOperation.addToQueue(queue)
@@ -73,4 +66,142 @@ internal class ConcurrentOperationTests: XCTestCase {
XCTAssertEqual(queue.operationCount, 1)
XCTAssertEqual(queue.operations, [concurrentOperation])
}
+
+ internal func testSimpleRetry() {
+ let queue = Queuer(name: "ConcurrentOperationTestSimpleRetry")
+
+ let testExpectation = expectation(description: "Simple Retry")
+
+ let concurrentOperation = ConcurrentOperation { operation in
+ operation.hasFailed = true
+ }
+ queue.addCompletionHandler {
+ testExpectation.fulfill()
+ }
+ concurrentOperation.addToQueue(queue)
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertTrue(concurrentOperation.hasFailed)
+ XCTAssertEqual(concurrentOperation.currentAttempt, 3)
+ }
+ }
+
+ internal func testChainedRetry() {
+ let queue = Queuer(name: "ConcurrentOperationTestChainedRetry")
+ let testExpectation = expectation(description: "Chained Retry")
+ var order: [Int] = []
+
+ let concurrentOperation1 = ConcurrentOperation { operation in
+ Thread.sleep(forTimeInterval: 1)
+ order.append(0)
+ operation.hasFailed = true
+ }
+ let concurrentOperation2 = ConcurrentOperation { operation in
+ order.append(1)
+ operation.hasFailed = true
+ }
+ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
+ order.append(2)
+ testExpectation.fulfill()
+ }
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2])
+ }
+ }
+
+ internal func testCanceledChainedRetry() {
+ let queue = Queuer(name: "ConcurrentOperationTestCanceledChainedRetry")
+ let testExpectation = expectation(description: "Canceled Chained Retry")
+ var order: [Int] = []
+
+ let concurrentOperation1 = ConcurrentOperation { operation in
+ Thread.sleep(forTimeInterval: 1)
+ order.append(0)
+ operation.hasFailed = true
+ }
+ let concurrentOperation2 = ConcurrentOperation { operation in
+ operation.cancel()
+ guard !operation.isCancelled else {
+ return
+ }
+ order.append(1)
+ operation.hasFailed = true
+ }
+ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
+ order.append(2)
+ testExpectation.fulfill()
+ }
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [0, 0, 0, 2])
+ }
+ }
+
+ internal func testChainedManualRetry() {
+ let queue = Queuer(name: "ConcurrentOperationTestChainedManualRetry")
+ let testExpectation = expectation(description: "Chained Manual Retry")
+ var order: [Int] = []
+
+ let concurrentOperation1 = ConcurrentOperation { operation in
+ order.append(0)
+ operation.hasFailed = true
+ }
+ concurrentOperation1.manualRetry = true
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
+ concurrentOperation1.retry()
+ }
+ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
+ concurrentOperation1.retry()
+ }
+ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
+ concurrentOperation1.retry()
+ }
+
+ let concurrentOperation2 = ConcurrentOperation { operation in
+ order.append(1)
+ operation.hasFailed = true
+ }
+ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
+ order.append(2)
+ testExpectation.fulfill()
+ }
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2])
+ }
+ }
+
+ internal func testChainedWrongManualRetry() {
+ let queue = Queuer(name: "ConcurrentOperationTestChainedWrongManualRetry")
+ let testExpectation = expectation(description: "Chained Wrong Manual Retry")
+ var order: [Int] = []
+
+ let concurrentOperation1 = ConcurrentOperation { operation in
+ order.append(0)
+ operation.hasFailed = true
+ }
+ concurrentOperation1.manualRetry = true
+
+ let concurrentOperation2 = ConcurrentOperation { _ in
+ order.append(1)
+ }
+ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
+ order.append(2)
+ }
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
+ testExpectation.fulfill()
+ }
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [0])
+ }
+ }
}
diff --git a/Tests/QueuerTests/QueuerTests+XCTest.swift b/Tests/QueuerTests/QueuerTests+XCTest.swift
new file mode 100644
index 0000000..bfe5de0
--- /dev/null
+++ b/Tests/QueuerTests/QueuerTests+XCTest.swift
@@ -0,0 +1,57 @@
+//
+// QueuerTests+XCTest.swift
+// Queuer
+//
+// MIT License
+//
+// Copyright (c) 2017 - 2018 Fabrizio Brancati
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//
+//
+// NOTE: This file was generated by generate_linux_tests.rb
+//
+// Do NOT edit this file directly as it will be regenerated automatically when needed.
+//
+
+import XCTest
+
+internal extension QueuerTests {
+ internal static var allTests: [(String, (QueuerTests) -> () throws -> Void)] {
+ return [
+ ("testOperationCount", testOperationCount),
+ ("testOperations", testOperations),
+ ("testMaxConcurrentOperationCount", testMaxConcurrentOperationCount),
+ ("testQualityOfService", testQualityOfService),
+ ("testInitWithNameMaxConcurrentOperationCount", testInitWithNameMaxConcurrentOperationCount),
+ ("testInitWithNameMaxConcurrentOperationCountQualityOfService", testInitWithNameMaxConcurrentOperationCountQualityOfService),
+ ("testAddOperationBlock", testAddOperationBlock),
+ ("testAddOperation", testAddOperation),
+ ("testAddOperations", testAddOperations),
+ ("testAddChainedOperations", testAddChainedOperations),
+ ("testAddChainedOperationsList", testAddChainedOperationsList),
+ ("testAddChainedOperationsEmpty", testAddChainedOperationsEmpty),
+ ("testAddChainedOperationsWithoutCompletion", testAddChainedOperationsWithoutCompletion),
+ ("testCancelAll", testCancelAll),
+ ("testPauseAndResume", testPauseAndResume),
+ ("testWaitUnitlAllOperationsAreFinished", testWaitUnitlAllOperationsAreFinished)
+ ]
+ }
+}
diff --git a/Tests/QueuerTests/QueuerTests.swift b/Tests/QueuerTests/QueuerTests.swift
index 16e50ec..7976beb 100644
--- a/Tests/QueuerTests/QueuerTests.swift
+++ b/Tests/QueuerTests/QueuerTests.swift
@@ -28,34 +28,14 @@ import Dispatch
@testable import Queuer
import XCTest
-// swiftlint:disable type_body_length
internal class QueuerTests: XCTestCase {
- internal static let allTests = [
- ("testOperationCount", testOperationCount),
- ("testOperations", testOperations),
- ("testMaxConcurrentOperationCount", testMaxConcurrentOperationCount),
- ("testQualityOfService", testQualityOfService),
- ("testInitWithNameMaxConcurrentOperationCount", testInitWithNameMaxConcurrentOperationCount),
- ("testInitWithNameMaxConcurrentOperationCountQualityOfService", testInitWithNameMaxConcurrentOperationCountQualityOfService),
- ("testAddOperationBlock", testAddOperationBlock),
- ("testAddOperation", testAddOperation),
- ("testAddOperations", testAddOperations),
- ("testAddChainedOperations", testAddChainedOperations),
- ("testAddChainedOperationsList", testAddChainedOperationsList),
- ("testAddChainedOperationsEmpty", testAddChainedOperationsEmpty),
- ("testAddChainedOperationsWithoutCompletion", testAddChainedOperationsWithoutCompletion),
- ("testCancelAll", testCancelAll),
- ("testPauseAndResume", testPauseAndResume),
- ("testWaitUnitlAllOperationsAreFinished", testWaitUnitlAllOperationsAreFinished)
- ]
-
internal func testOperationCount() {
let queue = Queuer(name: "QueuerTestOperationCount")
let testExpectation = expectation(description: "Operation Count")
XCTAssertEqual(queue.operationCount, 0)
- let concurrentOperation = ConcurrentOperation {
+ let concurrentOperation = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
testExpectation.fulfill()
}
@@ -72,7 +52,7 @@ internal class QueuerTests: XCTestCase {
let queue = Queuer(name: "QueuerTestOperations")
let testExpectation = expectation(description: "Operations")
- let concurrentOperation = ConcurrentOperation {
+ let concurrentOperation = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
testExpectation.fulfill()
}
@@ -129,7 +109,6 @@ internal class QueuerTests: XCTestCase {
waitForExpectations(timeout: 5) { error in
XCTAssertNil(error)
- XCTAssertEqual(queue.operationCount, 0)
}
}
@@ -137,7 +116,7 @@ internal class QueuerTests: XCTestCase {
let queue = Queuer(name: "QueuerTestAddOperation")
let testExpectation = expectation(description: "Add Operation")
- let concurrentOperation = ConcurrentOperation {
+ let concurrentOperation = ConcurrentOperation { _ in
XCTAssertEqual(queue.operationCount, 1)
testExpectation.fulfill()
}
@@ -154,17 +133,16 @@ internal class QueuerTests: XCTestCase {
let testExpectation = expectation(description: "Add Operations")
var check = 0
- let concurrentOperation1 = ConcurrentOperation {
+ let concurrentOperation1 = ConcurrentOperation { _ in
check += 1
}
- let concurrentOperation2 = ConcurrentOperation {
+ let concurrentOperation2 = ConcurrentOperation { _ in
check += 1
}
queue.addOperation(concurrentOperation1)
queue.addOperation(concurrentOperation2)
- let deadline = DispatchTime.now() + .seconds(2)
- DispatchQueue.global(qos: .background).asyncAfter(deadline: deadline) {
+ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
testExpectation.fulfill()
}
@@ -180,11 +158,11 @@ internal class QueuerTests: XCTestCase {
let testExpectation = expectation(description: "Add Chained Operations")
var order: [Int] = []
- let concurrentOperation1 = ConcurrentOperation {
+ let concurrentOperation1 = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
order.append(0)
}
- let concurrentOperation2 = ConcurrentOperation {
+ let concurrentOperation2 = ConcurrentOperation { _ in
order.append(1)
}
queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
@@ -203,11 +181,11 @@ internal class QueuerTests: XCTestCase {
let testExpectation = expectation(description: "Add Chained Operations List")
var order: [Int] = []
- let concurrentOperation1 = ConcurrentOperation {
+ let concurrentOperation1 = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
order.append(0)
}
- let concurrentOperation2 = ConcurrentOperation {
+ let concurrentOperation2 = ConcurrentOperation { _ in
order.append(1)
}
queue.addChainedOperations(concurrentOperation1, concurrentOperation2) {
@@ -240,10 +218,10 @@ internal class QueuerTests: XCTestCase {
let testExpectation = expectation(description: "Add Chained Operations Without Completion")
var order: [Int] = []
- let concurrentOperation1 = ConcurrentOperation {
+ let concurrentOperation1 = ConcurrentOperation { _ in
order.append(0)
}
- let concurrentOperation2 = ConcurrentOperation {
+ let concurrentOperation2 = ConcurrentOperation { _ in
order.append(1)
testExpectation.fulfill()
}
@@ -261,11 +239,11 @@ internal class QueuerTests: XCTestCase {
let testExpectation = expectation(description: "Cancell All Operations")
var order: [Int] = []
- let concurrentOperation1 = SynchronousOperation {
+ let concurrentOperation1 = SynchronousOperation { _ in
Thread.sleep(forTimeInterval: 2)
order.append(0)
}
- let concurrentOperation2 = SynchronousOperation {
+ let concurrentOperation2 = SynchronousOperation { _ in
order.append(1)
}
queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
@@ -290,11 +268,11 @@ internal class QueuerTests: XCTestCase {
let testExpectation = expectation(description: "Pause and Resume")
var order: [Int] = []
- let concurrentOperation1 = ConcurrentOperation {
+ let concurrentOperation1 = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
order.append(0)
}
- let concurrentOperation2 = ConcurrentOperation {
+ let concurrentOperation2 = ConcurrentOperation { _ in
order.append(1)
}
queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
@@ -322,11 +300,11 @@ internal class QueuerTests: XCTestCase {
let testExpectation = expectation(description: "Wait Unitl All Operations Are Finished")
var order: [Int] = []
- let concurrentOperation1 = ConcurrentOperation {
+ let concurrentOperation1 = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
order.append(0)
}
- let concurrentOperation2 = ConcurrentOperation {
+ let concurrentOperation2 = ConcurrentOperation { _ in
order.append(1)
}
queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) {
diff --git a/Tests/QueuerTests/RequestOperationTests.swift b/Tests/QueuerTests/RequestOperationTests.swift
deleted file mode 100644
index b0f5422..0000000
--- a/Tests/QueuerTests/RequestOperationTests.swift
+++ /dev/null
@@ -1,200 +0,0 @@
-//
-// RequestOperationTests.swift
-// Queuer
-//
-// MIT License
-//
-// Copyright (c) 2017 - 2018 Fabrizio Brancati
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-#if !os(Linux)
-
-@testable import Queuer
-import XCTest
-
-internal class RequestOperationTests: XCTestCase {
- internal static let allTests = [
- ("testInitFull", testInitFull),
- ("testExecute", testExecute),
- ("testUnsupportedURL", testUnsupportedURL),
- ("testWrongURL", testWrongURL),
- ("testWithoutCompletionHandler", testWithoutCompletionHandler),
- ("testCancel", testCancel),
- ("testPauseAndResume", testPauseAndResume)
- ]
-
- internal let testAddress: String = "https://google.com"
-
- override internal func setUp() {
- super.setUp()
-
- RequestOperation.globalCachePolicy = .reloadIgnoringLocalCacheData
- }
-
- internal func testInit() {
- let queue = Queuer(name: "RequestOperationTestInit")
-
- let requestOperation = RequestOperation()
- requestOperation.addToQueue(queue)
-
- XCTAssertNil(requestOperation.url?.absoluteString)
- XCTAssertNil(requestOperation.query)
- XCTAssertNil(requestOperation.completeURL)
- XCTAssertEqual(requestOperation.timeout, 30)
- XCTAssertEqual(requestOperation.method, .get)
- XCTAssertEqual(requestOperation.headers ?? [:], [:])
- XCTAssertNil(requestOperation.body)
- }
-
- internal func testInitFull() {
- let queue = Queuer(name: "RequestOperationTestInitFull")
- let testExpectation = expectation(description: "InitFull")
-
- let requestOperation = RequestOperation(url: self.testAddress, query: ["test": "test", "test2": "test2"], timeout: 30, method: .get, headers: ["test": "test", "test2": "test2"], body: Data()) { _, _, _, _ in
- testExpectation.fulfill()
- }
- requestOperation.addToQueue(queue)
-
- XCTAssertEqual(requestOperation.url?.absoluteString, self.testAddress)
- XCTAssertEqual(requestOperation.query, "?test=test&test2=test2")
- XCTAssertEqual(requestOperation.completeURL, URL(string: self.testAddress + "?test=test&test2=test2"))
- XCTAssertEqual(requestOperation.timeout, 30)
- XCTAssertEqual(requestOperation.method, .get)
- XCTAssertEqual(requestOperation.headers ?? [:], ["test": "test", "test2": "test2"])
- XCTAssertEqual(requestOperation.body, Data())
-
- waitForExpectations(timeout: 5) { error in
- XCTAssertNil(error)
- }
- }
-
- internal func testExecute() {
- let queue = Queuer(name: "RequestOperationTestExecute")
- let testExpectation = expectation(description: "Execute")
-
- let requestOperation = RequestOperation(url: self.testAddress) { success, _, _, error in
- XCTAssertNil(error)
- XCTAssertTrue(success)
- testExpectation.fulfill()
- }
- requestOperation.addToQueue(queue)
-
- waitForExpectations(timeout: 5) { error in
- XCTAssertNil(error)
- }
- }
-
- internal func testUnsupportedURL() {
- let queue = Queuer(name: "RequestOperationTestUnsupportedURL")
- let testExpectation = expectation(description: "Unsupported URL")
-
- let requestOperation = RequestOperation(url: "/path/to/something") { success, _, _, error in
- XCTAssertTrue(error is URLError)
- XCTAssertFalse(success)
- testExpectation.fulfill()
- }
- requestOperation.addToQueue(queue)
-
- waitForExpectations(timeout: 5) { error in
- XCTAssertNil(error)
- }
- }
-
- internal func testWrongURL() {
- let queue = Queuer(name: "RequestOperationTestWrongURL")
- let testExpectation = expectation(description: "Wrong URL")
-
- let requestOperation = RequestOperation(url: "👍") { success, _, _, error in
- XCTAssertEqual(error as? RequestOperation.RequestError, RequestOperation.RequestError.urlError)
- XCTAssertFalse(success)
- testExpectation.fulfill()
- }
- requestOperation.addToQueue(queue)
-
- waitForExpectations(timeout: 5) { error in
- XCTAssertNil(error)
- }
- }
-
- internal func testWithoutCompletionHandler() {
- let queue = Queuer(name: "RequestOperationTestWithoutCompletionHandler")
- let requestOperation = RequestOperation(url: self.testAddress)
- requestOperation.addToQueue(queue)
-
- XCTAssertEqual(queue.operations, [requestOperation])
- XCTAssertEqual(queue.operationCount, 1)
- }
-
- internal func testCancel() {
- let queue = Queuer(name: "RequestOperationTestCancel")
- let testExpectation = expectation(description: "Cancel")
-
- let requestOperation = RequestOperation(url: "http://fakehttpaddress.com/", cachePolicy: .reloadIgnoringLocalCacheData) { success, _, _, _ in
- // Currently there is no easy way to check in time if the operation was cancelled before completion.
- // XCTAssertEqual(error as? RequestOperation.RequestError, RequestOperation.RequestError.operationCancelled)
- XCTAssertFalse(success)
- testExpectation.fulfill()
- }
- requestOperation.addToQueue(queue)
-
- requestOperation.cancel()
-
- waitForExpectations(timeout: 5) { error in
- XCTAssertNil(error)
- }
- }
-
- internal func testPauseAndResume() {
- let queue = Queuer(name: "RequestOperationTestPauseAndResume")
- let testExpectation = expectation(description: "Pause and Resume")
- var order: [Int] = []
-
- let requestOperation1 = RequestOperation(url: self.testAddress) { success, _, _, error in
- XCTAssertNil(error)
- XCTAssertTrue(success)
- order.append(0)
- }
- let requestOperation2 = RequestOperation(url: self.testAddress) { success, _, _, error in
- XCTAssertNil(error)
- XCTAssertTrue(success)
- order.append(1)
- }
- queue.addChainedOperations([requestOperation1, requestOperation2]) {
- order.append(2)
- }
-
- queue.pause()
- testExpectation.fulfill()
-
- XCTAssertLessThanOrEqual(queue.operationCount, 3)
-
- waitForExpectations(timeout: 5) { error in
- XCTAssertNil(error)
- XCTAssertFalse(queue.isExecuting)
- XCTAssertLessThanOrEqual(queue.operationCount, 3)
- XCTAssertNotEqual(order, [0, 1, 2])
-
- queue.resume()
- XCTAssertTrue(queue.isExecuting)
- }
- }
-}
-
-#endif
diff --git a/Sources/Queuer/URLBuilder.swift b/Tests/QueuerTests/SchedulerTests+XCTest.swift
similarity index 56%
rename from Sources/Queuer/URLBuilder.swift
rename to Tests/QueuerTests/SchedulerTests+XCTest.swift
index c139701..c893436 100644
--- a/Sources/Queuer/URLBuilder.swift
+++ b/Tests/QueuerTests/SchedulerTests+XCTest.swift
@@ -1,5 +1,5 @@
//
-// URLBuilder.swift
+// SchedulerTests+XCTest.swift
// Queuer
//
// MIT License
@@ -23,28 +23,22 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
+//
+//
+//
+// NOTE: This file was generated by generate_linux_tests.rb
+//
+// Do NOT edit this file directly as it will be regenerated automatically when needed.
+//
-import Foundation
+import XCTest
-/// URL builder struct.
-internal enum URLBuilder {
- /// Builds the query as a string, ready to be added in the URL.
- ///
- /// - Parameter query: Query dictionary.
- /// - Returns: Returns the query as a String.
- internal static func build(query: [String: String]?) -> String {
- guard let query = query else {
- return ""
- }
-
- var finalQuery: String = ""
- for (index, parameter) in query.enumerated() {
- guard let parameterKey = parameter.key.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed), let parameterValue = parameter.value.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else {
- continue
- }
- finalQuery += index == 0 ? "?" : "&"
- finalQuery += parameterKey + "=" + parameterValue
- }
- return finalQuery
+internal extension SchedulerTests {
+ internal static var allTests: [(String, (SchedulerTests) -> () throws -> Void)] {
+ return [
+ ("testInitWithoutHandler", testInitWithoutHandler),
+ ("testInitWithHandler", testInitWithHandler),
+ ("testCancel", testCancel)
+ ]
}
}
diff --git a/Tests/QueuerTests/SchedulerTests.swift b/Tests/QueuerTests/SchedulerTests.swift
new file mode 100644
index 0000000..395e8c8
--- /dev/null
+++ b/Tests/QueuerTests/SchedulerTests.swift
@@ -0,0 +1,89 @@
+//
+// SchedulerTests.swift
+// Queuer
+//
+// MIT License
+//
+// Copyright (c) 2017 - 2018 Fabrizio Brancati
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+import Dispatch
+@testable import Queuer
+import XCTest
+
+internal class SchedulerTests: XCTestCase {
+ internal func testInitWithoutHandler() {
+ let testExpectation = expectation(description: "Init Without Handler")
+ var order: [Int] = []
+
+ var schedule = Scheduler(deadline: .now(), repeating: .seconds(1))
+ schedule.setHandler {
+ order.append(0)
+ }
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(3500)) {
+ testExpectation.fulfill()
+ }
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [0 ,0 ,0, 0])
+ }
+ }
+
+ internal func testInitWithHandler() {
+ let testExpectation = expectation(description: "Init With Handler")
+ var order: [Int] = []
+
+ let schedule = Scheduler(deadline: .now(), repeating: .never) {
+ order.append(0)
+ }
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(3500)) {
+ testExpectation.fulfill()
+ }
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [0])
+ schedule.timer.cancel()
+ }
+ }
+
+ internal func testCancel() {
+ let testExpectation = expectation(description: "Init Without Handler")
+ var order: [Int] = []
+
+ var schedule = Scheduler(deadline: .now(), repeating: .seconds(1))
+ schedule.setHandler {
+ order.append(0)
+ schedule.timer.cancel()
+ }
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(3500)) {
+ testExpectation.fulfill()
+ }
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [0])
+ }
+ }
+}
diff --git a/Tests/QueuerTests/SemaphoreTests+XCTest.swift b/Tests/QueuerTests/SemaphoreTests+XCTest.swift
new file mode 100644
index 0000000..9e795ba
--- /dev/null
+++ b/Tests/QueuerTests/SemaphoreTests+XCTest.swift
@@ -0,0 +1,43 @@
+//
+// SemaphoreTests+XCTest.swift
+// Queuer
+//
+// MIT License
+//
+// Copyright (c) 2017 - 2018 Fabrizio Brancati
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//
+//
+// NOTE: This file was generated by generate_linux_tests.rb
+//
+// Do NOT edit this file directly as it will be regenerated automatically when needed.
+//
+
+import XCTest
+
+internal extension SemaphoreTests {
+ internal static var allTests: [(String, (SemaphoreTests) -> () throws -> Void)] {
+ return [
+ ("testWithSemaphore", testWithSemaphore),
+ ("testWithoutSemaphore", testWithoutSemaphore)
+ ]
+ }
+}
diff --git a/Tests/QueuerTests/SemaphoreTests.swift b/Tests/QueuerTests/SemaphoreTests.swift
index 82f08f6..038f186 100644
--- a/Tests/QueuerTests/SemaphoreTests.swift
+++ b/Tests/QueuerTests/SemaphoreTests.swift
@@ -28,18 +28,13 @@
import XCTest
internal class SemaphoreTests: XCTestCase {
- internal static let allTests = [
- ("testWithSemaphore", testWithSemaphore),
- ("testWithoutSemaphore", testWithoutSemaphore)
- ]
-
internal func testWithSemaphore() {
let semaphore = Semaphore()
let queue = Queuer(name: "SemaphoreTestWithSemaphore")
let testExpectation = expectation(description: "With Semaphore")
var testString = ""
- let concurrentOperation = ConcurrentOperation {
+ let concurrentOperation = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
testString = "Tested"
semaphore.continue()
@@ -60,7 +55,7 @@ internal class SemaphoreTests: XCTestCase {
let testExpectation = expectation(description: "Without Semaphore")
var testString = ""
- let concurrentOperation = ConcurrentOperation {
+ let concurrentOperation = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: 2)
testString = "Tested"
testExpectation.fulfill()
diff --git a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift
new file mode 100644
index 0000000..e8a4e19
--- /dev/null
+++ b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift
@@ -0,0 +1,45 @@
+//
+// SynchronousOperationTests+XCTest.swift
+// Queuer
+//
+// MIT License
+//
+// Copyright (c) 2017 - 2018 Fabrizio Brancati
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//
+//
+// NOTE: This file was generated by generate_linux_tests.rb
+//
+// Do NOT edit this file directly as it will be regenerated automatically when needed.
+//
+
+import XCTest
+
+internal extension SynchronousOperationTests {
+ internal static var allTests: [(String, (SynchronousOperationTests) -> () throws -> Void)] {
+ return [
+ ("testSynchronousOperation", testSynchronousOperation),
+ ("testSynchronousOperationOnSharedQueuer", testSynchronousOperationOnSharedQueuer),
+ ("testSynchronousOperationRetry", testSynchronousOperationRetry),
+ ("testCancel", testCancel)
+ ]
+ }
+}
diff --git a/Tests/QueuerTests/SynchronousOperationTests.swift b/Tests/QueuerTests/SynchronousOperationTests.swift
index b0dcffa..6f5d688 100644
--- a/Tests/QueuerTests/SynchronousOperationTests.swift
+++ b/Tests/QueuerTests/SynchronousOperationTests.swift
@@ -29,21 +29,15 @@ import Dispatch
import XCTest
internal class SynchronousOperationTests: XCTestCase {
- internal static let allTests = [
- ("testSynchronousOperation", testSynchronousOperation),
- ("testSynchronousOperationOnSharedQueuer", testSynchronousOperationOnSharedQueuer),
- ("testCancel", testCancel)
- ]
-
internal func testSynchronousOperation() {
let queue = Queuer(name: "SynchronousOperationTestSynchronousOperation")
let testExpectation = expectation(description: "Synchronous Operation")
var testString = ""
- let synchronousOperation1 = SynchronousOperation {
+ let synchronousOperation1 = SynchronousOperation { _ in
testString = "Tested1"
}
- let synchronousOperation2 = SynchronousOperation {
+ let synchronousOperation2 = SynchronousOperation { _ in
Thread.sleep(forTimeInterval: 2)
testString = "Tested2"
@@ -65,10 +59,10 @@ internal class SynchronousOperationTests: XCTestCase {
let testExpectation = expectation(description: "Synchronous Operation")
var testString = ""
- let synchronousOperation1 = SynchronousOperation {
+ let synchronousOperation1 = SynchronousOperation { _ in
testString = "Tested1"
}
- let synchronousOperation2 = SynchronousOperation {
+ let synchronousOperation2 = SynchronousOperation { _ in
Thread.sleep(forTimeInterval: 2)
testString = "Tested2"
@@ -86,6 +80,35 @@ internal class SynchronousOperationTests: XCTestCase {
}
}
+ internal func testSynchronousOperationRetry() {
+ let queue = Queuer(name: "SynchronousOperationTestRetry")
+ let testExpectation = expectation(description: "Synchronous Operation Retry")
+ var order: [Int] = []
+
+ let synchronousOperation1 = SynchronousOperation { operation in
+ Thread.sleep(forTimeInterval: 1)
+ order.append(0)
+ operation.hasFailed = true
+
+ if operation.currentAttempt == 3 {
+ testExpectation.fulfill()
+ }
+ }
+ let synchronousOperation2 = SynchronousOperation { _ in
+ order.append(1)
+ }
+ synchronousOperation1.addToQueue(queue)
+ synchronousOperation2.addToQueue(queue)
+
+ XCTAssertFalse(synchronousOperation1.isAsynchronous)
+ XCTAssertFalse(synchronousOperation2.isAsynchronous)
+
+ waitForExpectations(timeout: 5) { error in
+ XCTAssertNil(error)
+ XCTAssertEqual(order, [1, 0, 0, 0])
+ }
+ }
+
internal func testCancel() {
let queue = Queuer(name: "SynchronousOperationTestCancel")
queue.maxConcurrentOperationCount = 1
@@ -98,11 +121,11 @@ internal class SynchronousOperationTests: XCTestCase {
testExpectation.fulfill()
}
- let synchronousOperation1 = SynchronousOperation {
+ let synchronousOperation1 = SynchronousOperation { _ in
testString = "Tested1"
Thread.sleep(forTimeInterval: 4)
}
- let synchronousOperation2 = SynchronousOperation {
+ let synchronousOperation2 = SynchronousOperation { _ in
testString = "Tested2"
}
synchronousOperation1.addToQueue(queue)
diff --git a/Tests/QueuerTests/URLBuilderTests.swift b/Tests/QueuerTests/URLBuilderTests.swift
deleted file mode 100644
index d730d6d..0000000
--- a/Tests/QueuerTests/URLBuilderTests.swift
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// URLBuilderTests.swift
-// Queuer
-//
-// MIT License
-//
-// Copyright (c) 2017 - 2018 Fabrizio Brancati
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-@testable import Queuer
-import XCTest
-
-internal class URLBuilderTests: XCTestCase {
- internal static let allTests = [
- ("testWithoutParameters", testWithoutParameters),
- ("testWithSingleParameter", testBuildURLWithSingleParameter),
- ("testWithMultipleParameters", testWithMultipleParameters),
- ("testWithEmojiCharctersInParameters", testWithEmojiCharctersInParameters)
- //("testWithStrangeCharctersInParameters", testWithStrangeCharctersInParameters)
- ]
-
- internal func testWithoutParameters() {
- let query = URLBuilder.build(query: [:])
-
- XCTAssertEqual(query, "")
- }
-
- internal func testBuildURLWithSingleParameter() {
- let query = URLBuilder.build(query: ["test": "test"])
-
- XCTAssertEqual(query, "?test=test")
- }
-
- internal func testWithMultipleParameters() {
- let query = URLBuilder.build(query: ["test": "test", "test2": "test2"])
-
- XCTAssert(query == "?test=test&test2=test2" || query == "?test2=test2&test=test")
- }
-
- internal func testWithEmojiCharctersInParameters() {
- let query = URLBuilder.build(query: ["test": "test", "test👍": "test👍"])
-
- XCTAssert(query == "?test=test&test%F0%9F%91%8D=test%F0%9F%91%8D" || query == "?test%F0%9F%91%8D=test%F0%9F%91%8D&test=test")
- }
-
- /// Thanks to [Stack Overflow](https://stackoverflow.com/a/33558934/4032046 ).
- internal func testWithStrangeCharctersInParameters() {
- guard let string = String(bytes: [0xD8, 0x00] as [UInt8], encoding: String.Encoding.utf16BigEndian) else {
- XCTFail("`testWithStrangeCharctersInParameters` error")
- return
- }
-
- let query = URLBuilder.build(query: [string: "test", "test👍": string])
- XCTAssertEqual(query, "")
- }
-}
diff --git a/generate_linux_tests.rb b/generate_linux_tests.rb
new file mode 100644
index 0000000..8727017
--- /dev/null
+++ b/generate_linux_tests.rb
@@ -0,0 +1,245 @@
+#!/usr/bin/env ruby
+
+#
+# process_test_files.rb
+#
+# Copyright 2016 Tony Stone
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Created by Tony Stone on 5/4/16.
+#
+require 'getoptlong'
+require 'fileutils'
+require 'pathname'
+
+include FileUtils
+
+#
+# This ruby script will auto generate LinuxMain.swift and the +XCTest.swift extension files for Swift Package Manager on Linux platforms.
+#
+# See https://github.com/apple/swift-corelibs-xctest/blob/master/Documentation/Linux.md
+#
+def header(file_name)
+ string = <<-eos
+//
+//
+// Queuer
+//
+// MIT License
+//
+// Copyright (c) 2017 - 2018 Fabrizio Brancati
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//
+//
+// NOTE: This file was generated by generate_linux_tests.rb
+//
+// Do NOT edit this file directly as it will be regenerated automatically when needed.
+//
+
+import XCTest
+ eos
+
+ string
+ .sub('', File.basename(file_name))
+ .sub('', Time.now.to_s)
+end
+
+def create_extension_file(file_name, classes)
+ extension_file = file_name.sub! '.swift', '+XCTest.swift'
+ print 'Creating file: ' + extension_file + "\n"
+
+ File.open(extension_file, 'w') do |file|
+ file.write header(extension_file)
+ file.write "\n"
+
+ for class_array in classes
+ file.write 'internal extension ' + class_array[0] + " {\n"
+ file.write ' internal static var allTests: [(String, (' + class_array[0] + ") -> () throws -> Void)] {\n"
+ file.write " return [\n"
+
+ class_count = class_array[1].size
+ count = 0
+ for func_name in class_array[1]
+ count += 1
+
+ file.write ' ("' + func_name + '", ' + func_name + (count == class_count ? ")\n" : "),\n")
+ end
+
+ file.write " ]\n"
+ file.write " }\n"
+ file.write "}\n"
+ end
+ end
+end
+
+def create_linux_main(tests_directory, all_test_sub_directories, files)
+ file_name = tests_directory + '/LinuxMain.swift'
+ print 'Creating file: ' + file_name + "\n"
+
+ File.open(file_name, 'w') do |file|
+ file.write header(file_name)
+ file.write "\n"
+
+ file.write "#if os(Linux) || os(FreeBSD)\n"
+ for test_sub_directory in all_test_sub_directories.sort { |x, y| x <=> y }
+ file.write ' @testable import ' + test_sub_directory + "\n"
+ end
+ file.write "\n"
+ file.write " XCTMain([\n"
+
+ test_cases = []
+ for classes in files
+ for class_array in classes
+ test_cases << class_array[0]
+ end
+ end
+
+ cases_count = test_cases.size
+ count = 0
+ for test_case in test_cases.sort { |x, y| x <=> y }
+ count += 1
+
+ file.write ' testCase(' + test_case + (count == cases_count ? ".allTests)\n" : ".allTests),\n")
+ end
+ file.write " ])\n"
+ file.write "#endif\n"
+ end
+end
+
+def parse_source_file(file_name)
+ puts 'Parsing file: ' + file_name + "\n"
+
+ classes = []
+ current_class = nil
+ in_if_linux = false
+ in_else = false
+ ignore = false
+
+ #
+ # Read the file line by line
+ # and parse to find the class
+ # names and func names
+ #
+ File.readlines(file_name).each do |line|
+ if in_if_linux
+ if /\#else/ =~ line
+ in_else = true
+ ignore = true
+ elsif /\#end/ =~ line
+ in_else = false
+ in_if_linux = false
+ ignore = false
+ end
+ elsif /\#if[ \t]+os\(Linux\)/ =~ line
+ in_if_linux = true
+ ignore = false
+ end
+
+ next if ignore
+ # Match class or func
+ match = line[/class[ \t]+[a-zA-Z0-9_]*(?=[ \t]*:[ \t]*XCTestCase)|func[ \t]+test[a-zA-Z0-9_]*(?=[ \t]*\(\))/, 0]
+ if match
+ if match[/class/, 0] == 'class'
+ class_name = match.sub(/^class[ \t]+/, '')
+ #
+ # Create a new class / func structure
+ # and add it to the classes array.
+ #
+ current_class = [class_name, []]
+ classes << current_class
+ else # Must be a func
+ func_name = match.sub(/^func[ \t]+/, '')
+ #
+ # Add each func name the the class / func
+ # structure created above.
+ #
+ current_class[1] << func_name
+ end
+ end
+ end
+ classes
+end
+
+#
+# Main routine
+#
+#
+
+tests_directory = 'Tests'
+
+options = GetoptLong.new(['--tests-dir', GetoptLong::OPTIONAL_ARGUMENT])
+options.quiet = true
+
+begin
+ options.each do |option, value|
+ case option
+ when '--tests-dir'
+ tests_directory = value
+ end
+ end
+ rescue GetoptLong::InvalidOption
+end
+
+all_test_sub_directories = []
+all_files = []
+
+Dir[tests_directory + '/*'].each do |sub_directory|
+ next unless File.directory?(sub_directory)
+ directory_has_classes = false
+ Dir[sub_directory + '/*Test{s,}.swift'].each do |file_name|
+ next unless File.file? file_name
+ file_classes = parse_source_file(file_name)
+
+ #
+ # If there are classes in the
+ # test source file, create an extension
+ # file for it.
+ #
+ next unless file_classes.count.positive?
+ create_extension_file(file_name, file_classes)
+ directory_has_classes = true
+ all_files << file_classes
+ end
+
+ if directory_has_classes
+ all_test_sub_directories << Pathname.new(sub_directory).split.last.to_s
+ end
+end
+
+#
+# Last step is the create a LinuxMain.swift file that
+# references all the classes and funcs in the source files.
+#
+if all_files.count.positive?
+ create_linux_main(tests_directory, all_test_sub_directories, all_files)
+end
+# eof
diff --git a/jazzy.sh b/jazzy.sh
index e49fa0d..c384069 100755
--- a/jazzy.sh
+++ b/jazzy.sh
@@ -2,7 +2,7 @@
# Creates documentation using Jazzy.
-FRAMEWORK_VERSION=1.3.2
+FRAMEWORK_VERSION=2.0.0
jazzy \
--clean \