1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-11-07 05:10:06 +01:00

♻️ Migrate more tests to Swift Testing

This commit is contained in:
2025-09-29 16:31:30 +02:00
parent 9c9720de42
commit 5b27d9f0ea
18 changed files with 330 additions and 364 deletions

View File

@@ -1361,6 +1361,11 @@
isa = PBXGroup;
children = (
C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */,
C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */,
C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */,
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */,
C4551656297AED18009B8466 /* ValetRcTest.swift */,
C456A0D02AA6175D0080144F /* Config */,
);
path = Parsers;
sourceTree = "<group>";
@@ -2188,11 +2193,6 @@
C4C1019727C65A11001FACC2 /* Parsers */ = {
isa = PBXGroup;
children = (
C456A0D02AA6175D0080144F /* Config */,
C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */,
C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */,
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */,
C4551656297AED18009B8466 /* ValetRcTest.swift */,
C40934AA298EEDA900D25014 /* CaskFileParserTest.swift */,
C4AFC4B229C4F43300BF4E0D /* HomebrewUpgradableTest.swift */,
C4F520662AF03791006787F2 /* ExtensionEnumeratorTest.swift */,

View File

@@ -26,34 +26,34 @@ struct Constants {
be displayed. This is based on an appropriate launch time on a
basic M1 Apple chip, with some margin for slower Intel chips.
*/
static let SlowBootThresholdInterval: TimeInterval = 30.0
static let SlowBootThresholdInterval: TimeInterval = .seconds(30)
/**
The interval between automatic background update checks.
*/
static let AutomaticUpdateCheckInterval: TimeInterval = 60.0 * 60 * 24 // 24 hours
static let AutomaticUpdateCheckInterval: TimeInterval = .hours(24)
/**
The minimum interval that must pass before allowing another
automatic update check. This prevents excessive checking
on frequent app restarts (due to crashes or bad config).
*/
static let MinimumUpdateCheckInterval: TimeInterval = 60.0 * 60 // 60 minutes
static let MinimumUpdateCheckInterval: TimeInterval = .minutes(60)
/**
Retry intervals for failed automatic update checks.
Uses exponential backoff before falling back to normal schedule.
*/
static let UpdateCheckRetryIntervals: [TimeInterval] = [
60 * 5, // 5 minutes
60 * 15, // 15 minutes
60 * 60, // 1 hour
60 * 60 * 3 // 3 hours (final attempt)
.minutes(5),
.minutes(15),
.hours(1),
.hours(3)
]
/**
PHP Monitor supplies a hardcoded list of PHP packages in its own
PHP Version Manager.
PHP Version Manager.
This hardcoded list will expire and will need to be modified when
the cutoff date occurs, which is when the `php` formula will
@@ -62,8 +62,12 @@ struct Constants {
If users launch an older version of the app, then a warning
will be displayed to let them know that certain operations
will not work correctly and that they need to update their app.
The cutoff date is always a few days after GA of the latest
release, as it often takes a while for Homebrew to make the
new release available and not everyone uses a separate tap.
*/
static let PhpFormulaeCutoffDate = "2025-11-30" // YYYY-MM-DD
static let PhpFormulaeCutoffDate = "2025-11-20" // YYYY-MM-DD
/**
* The PHP versions that are considered pre-release versions.
@@ -72,7 +76,8 @@ struct Constants {
*/
static var ExperimentalPhpVersions: Set<String> {
let releaseDates = [
"8.5": Date.fromString(Self.PhpFormulaeCutoffDate),
// "8.6": Date.fromString("2026-11-30"), // TBD
"8.5": Date.fromString(PhpFormulaeCutoffDate),
"8.4": Date.fromString("2024-11-22")
]
@@ -108,6 +113,7 @@ struct Constants {
"7.0", "7.1", "7.2", "7.3", "7.4",
"8.0", "8.1", "8.2", "8.3", "8.4",
"8.5" // DEV
// "8.6" // TBD
]
/**
@@ -130,48 +136,28 @@ struct Constants {
"7.1", "7.2", "7.3", "7.4",
"8.0", "8.1", "8.2", "8.3", "8.4",
"8.5" // DEV
// "8.6" // TBD
]
]
struct Urls {
// phpmon.app URLs (these are aliased to redirect correctly)
static let DonationPage = url("https://phpmon.app/sponsor")
static let DonationPage = URL(
string: "https://phpmon.app/sponsor"
)!
static let FrequentlyAskedQuestions = url("https://phpmon.app/faq")
static let FrequentlyAskedQuestions = URL(
string: "https://phpmon.app/faq"
)!
static let WikiPhpUnavailable = url("https://phpmon.app/php-unavailable")
static let WikiPhpUnavailable = URL(
string: "https://phpmon.app/php-unavailable"
)!
static let WikiPhpUpgrade = url("https://phpmon.app/php-upgrade")
static let WikiPhpUpgrade = URL(
string: "https://phpmon.app/php-upgrade"
)!
static let DonationPayment = url("https://phpmon.app/sponsor/now")
static let DonationPayment = URL(
string: "https://phpmon.app/sponsor/now"
)!
static let EarlyAccessChangelog = URL(
string: "https://phpmon.app/early-access/release-notes"
)!
static let EarlyAccessChangelog = url("https://phpmon.app/early-access/release-notes")
// API endpoints (via api.phpmon.app)
static let UpdateCheckEndpoint = URL(
string: "https://api.phpmon.app/api/v1/update-check"
)!
static let UpdateCheckEndpoint = url("https://api.phpmon.app/api/v1/update-check")
// GitHub URLs (do not alias these)
static let GitHubReleases = URL(
string: "https://github.com/nicoverbruggen/phpmon/releases"
)!
static let GitHubReleases = url("https://github.com/nicoverbruggen/phpmon/releases")
}
}

View File

@@ -52,7 +52,9 @@ func delay(seconds: Double) async {
try! await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
}
/** A simpler way to initialize a fixed, valid URL. */
/**
A simpler way to initialize a fixed, valid URL.
*/
func url(_ string: String) -> URL {
return URL(string: string)!
}

View File

@@ -9,7 +9,14 @@
import Foundation
extension TimeInterval {
public static func minutes(_ amount: Int) -> TimeInterval {
return Double(amount * 60)
static func seconds(_ value: Double) -> TimeInterval { value }
static func minutes(_ value: Double) -> TimeInterval { value * 60 }
static func hours(_ value: Double) -> TimeInterval { value * 3600 }
static func days(_ value: Double) -> TimeInterval { value * 86400 }
}
extension Date {
func adding(_ interval: TimeInterval) -> Date {
return self.addingTimeInterval(interval)
}
}

View File

@@ -1,42 +0,0 @@
//
// BytePhpPreferenceTest.swift
// Unit Tests
//
// Created by Nico Verbruggen on 04/09/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import XCTest
class BytePhpPreferenceTest: XCTestCase {
func test_can_extract_memory_value() throws {
let pref = BytePhpPreference(key: "memory_limit")
XCTAssertEqual(pref.internalValue, "512M")
XCTAssertEqual(pref.unit, .megabyte)
XCTAssertEqual(pref.value, 512)
}
func test_can_parse_all_kinds_of_values() throws {
var (unit, value) = BytePhpPreference.readFrom(internalValue: "1G")!
XCTAssertEqual(unit, .gigabyte)
XCTAssertEqual(value, 1)
(unit, value) = BytePhpPreference.readFrom(internalValue: "256M")!
XCTAssertEqual(unit, .megabyte)
XCTAssertEqual(value, 256)
(unit, value) = BytePhpPreference.readFrom(internalValue: "512K")!
XCTAssertEqual(unit, .kilobyte)
XCTAssertEqual(value, 512)
(unit, value) = BytePhpPreference.readFrom(internalValue: "1024")!
XCTAssertEqual(unit, .kilobyte)
XCTAssertEqual(value, 1024)
(unit, value) = BytePhpPreference.readFrom(internalValue: "-1")!
XCTAssertEqual(unit, .kilobyte)
XCTAssertEqual(value, -1)
}
}

View File

@@ -1,81 +0,0 @@
//
// NginxConfigurationTest.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 29/11/2021.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import XCTest
class NginxConfigurationTest: XCTestCase {
// MARK: - Test Files
static var regularUrl: URL {
return Bundle(for: Self.self).url(forResource: "nginx-site", withExtension: "test")!
}
static var isolatedUrl: URL {
return Bundle(for: Self.self).url(forResource: "nginx-site-isolated", withExtension: "test")!
}
static var proxyUrl: URL {
return Bundle(for: Self.self).url(forResource: "nginx-proxy", withExtension: "test")!
}
static var secureProxyUrl: URL {
return Bundle(for: Self.self).url(forResource: "nginx-secure-proxy", withExtension: "test")!
}
static var customTldProxyUrl: URL {
return Bundle(for: Self.self).url(forResource: "nginx-secure-proxy-custom-tld", withExtension: "test")!
}
// MARK: - Tests
func test_can_determine_site_name_and_tld() throws {
XCTAssertEqual(
"nginx-site",
NginxConfigurationFile.from(filePath: NginxConfigurationTest.regularUrl.path)?.domain
)
XCTAssertEqual(
"test",
NginxConfigurationFile.from(filePath: NginxConfigurationTest.regularUrl.path)?.tld
)
}
func test_can_determine_isolation() throws {
XCTAssertNil(
NginxConfigurationFile.from(filePath: NginxConfigurationTest.regularUrl.path)?.isolatedVersion
)
XCTAssertEqual(
"8.1",
NginxConfigurationFile.from(filePath: NginxConfigurationTest.isolatedUrl.path)?.isolatedVersion
)
}
func test_can_determine_proxy() throws {
let proxied = NginxConfigurationFile.from(filePath: NginxConfigurationTest.proxyUrl.path)!
XCTAssertTrue(proxied.contents.contains("# valet stub: proxy.valet.conf"))
XCTAssertEqual("http://127.0.0.1:90", proxied.proxy)
let normal = NginxConfigurationFile.from(filePath: NginxConfigurationTest.regularUrl.path)!
XCTAssertFalse(normal.contents.contains("# valet stub: proxy.valet.conf"))
XCTAssertEqual(nil, normal.proxy)
}
func test_can_determine_secured_proxy() throws {
let proxied = NginxConfigurationFile.from(filePath: NginxConfigurationTest.secureProxyUrl.path)!
XCTAssertTrue(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
XCTAssertEqual("http://127.0.0.1:90", proxied.proxy)
}
func test_can_determine_proxy_with_custom_tld() throws {
let proxied = NginxConfigurationFile.from(filePath: NginxConfigurationTest.customTldProxyUrl.path)!
XCTAssertTrue(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
XCTAssertEqual("http://localhost:8080", proxied.proxy)
}
}

View File

@@ -1,72 +0,0 @@
//
// ExtensionParserTest.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 13/02/2021.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import XCTest
class PhpExtensionTest: XCTestCase {
static var phpIniFileUrl: URL {
return Bundle(for: Self.self).url(forResource: "php", withExtension: "ini")!
}
func test_can_load_extension() throws {
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
XCTAssertGreaterThan(extensions.count, 0)
}
func test_extension_name_is_correct() throws {
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
let extensionNames = extensions.map { (ext) -> String in
return ext.name
}
// These 6 should be found
XCTAssertTrue(extensionNames.contains("xdebug"))
XCTAssertTrue(extensionNames.contains("imagick"))
XCTAssertTrue(extensionNames.contains("sodium-next"))
XCTAssertTrue(extensionNames.contains("opcache"))
XCTAssertTrue(extensionNames.contains("yaml"))
XCTAssertTrue(extensionNames.contains("custom"))
XCTAssertFalse(extensionNames.contains("fake"))
XCTAssertFalse(extensionNames.contains("nice"))
}
func test_extension_status_is_correct() throws {
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
// xdebug should be enabled
XCTAssertEqual(extensions[0].enabled, true)
// imagick should be disabled
XCTAssertEqual(extensions[1].enabled, false)
}
func test_toggle_works_as_expected() async throws {
let destination = Utility.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
let extensions = PhpExtension.from(filePath: destination.path)
XCTAssertEqual(extensions.count, 6)
// Try to disable xdebug (should be detected first)!
let xdebug = extensions.first!
XCTAssertTrue(xdebug.name == "xdebug")
XCTAssertEqual(xdebug.enabled, true)
await xdebug.toggle()
XCTAssertEqual(xdebug.enabled, false)
// Check if the file contains the appropriate data
let file = try! String(contentsOf: destination, encoding: .utf8)
XCTAssertTrue(file.contains("; zend_extension=\"xdebug.so\""))
// Make sure if we load the data again, it's disabled
XCTAssertEqual(PhpExtension.from(filePath: destination.path).first!.enabled, false)
}
}

View File

@@ -1,49 +0,0 @@
//
// ValetRcTest.swift
// Unit Tests
//
// Created by Nico Verbruggen on 20/01/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import XCTest
class ValetRcTest: XCTestCase {
// MARK: - Test Files
static var validPath: URL {
return Bundle(for: Self.self)
.url(forResource: "valetrc", withExtension: "valid")!
}
static var brokenPath: URL {
return Bundle(for: Self.self)
.url(forResource: "valetrc", withExtension: "broken")!
}
// MARK: - Tests
func test_can_extract_fields_from_valetrc_file() throws {
let fakeFile = RCFile.fromPath("/Users/fake/file.rc")
XCTAssertNil(fakeFile)
// Can parse the file
let validFile = RCFile.fromPath(ValetRcTest.validPath.path)
XCTAssertNotNil(validFile)
let fields = validFile!.fields
// Correctly parses and trims (and omits double quotes) per line
XCTAssertEqual(fields["PHP"], "php@8.2")
XCTAssertEqual(fields["OTHER"], "thing")
XCTAssertEqual(fields["PHPMON_WATCH"], "true")
XCTAssertEqual(fields["SYNTAX"], "variable")
// Ignores entries prefixed with #
XCTAssertTrue(!fields.keys.contains("#PHP"))
// Ignores invalid lines
XCTAssertTrue(!fields.keys.contains("OOF"))
}
}

View File

@@ -9,13 +9,14 @@
import Testing
import Foundation
@Suite("Api")
struct TestableApiTest {
@Test
func createFakeApi() {
@Test func createFakeApi() {
let api = TestableApi(responses: [
url("https://api.phpmon.test"): FakeApiResponse(statusCode: 200, headers: [:], text: "{\"success\": true}")
url("https://api.phpmon.test"): FakeApiResponse(
statusCode: 200,
headers: [:],
text: "{\"success\": true}"
)
])
#expect(api.hasResponse(for: url("https://api.phpmon.test")) == true)
@@ -25,5 +26,4 @@ struct TestableApiTest {
#expect(response.statusCode == 200)
#expect(response.text.contains("success"))
}
}

View File

@@ -8,11 +8,8 @@
import Testing
@Suite("Commands")
struct CommandTest {
@Test
func determinePhpVersion() {
@Test func determinePhpVersion() {
let version = Command.execute(
path: Paths.php,
arguments: ["-v"],
@@ -24,5 +21,4 @@ struct CommandTest {
#expect(version.contains("built"))
#expect(version.contains("Zend"))
}
}

View File

@@ -8,7 +8,6 @@
import Testing
@Suite("Integration")
struct PackagistTest {
@Test func canRetrieveLaravelValetVersion() async {
let packageToCheck = "laravel/valet"

View File

@@ -0,0 +1,41 @@
//
// BytePhpPreferenceTest.swift
// Unit Tests
//
// Created by Nico Verbruggen on 04/09/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Testing
struct BytePhpPreferenceTest {
@Test func test_can_extract_memory_value() throws {
let pref = BytePhpPreference(key: "memory_limit")
#expect(pref.internalValue == "512M")
#expect(pref.unit == .megabyte)
#expect(pref.value == 512)
}
@Test func test_can_parse_all_kinds_of_values() throws {
var (unit, value) = BytePhpPreference.readFrom(internalValue: "1G")!
#expect(unit == .gigabyte)
#expect(value == 1)
(unit, value) = BytePhpPreference.readFrom(internalValue: "256M")!
#expect(unit == .megabyte)
#expect(value == 256)
(unit, value) = BytePhpPreference.readFrom(internalValue: "512K")!
#expect(unit == .kilobyte)
#expect(value == 512)
(unit, value) = BytePhpPreference.readFrom(internalValue: "1024")!
#expect(unit == .kilobyte)
#expect(value == 1024)
(unit, value) = BytePhpPreference.readFrom(internalValue: "-1")!
#expect(unit == .kilobyte)
#expect(value == -1)
}
}

View File

@@ -6,41 +6,41 @@
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import XCTest
import Testing
import Foundation
class PhpConfigurationFileTest: XCTestCase {
class PhpConfigurationFileTest {
static var phpIniFileUrl: URL {
return Bundle(for: Self.self).url(forResource: "php", withExtension: "ini")!
return TestBundle.url(forResource: "php", withExtension: "ini")!
}
func test_can_load_extension() throws {
@Test func test_can_load_extension() throws {
let iniFile = PhpConfigurationFile.from(filePath: Self.phpIniFileUrl.path)
#expect(iniFile != nil)
#expect(!iniFile!.extensions.isEmpty)
}
@Test func test_can_check_key_existence() throws {
let iniFile = PhpConfigurationFile.from(filePath: Self.phpIniFileUrl.path)!
XCTAssertNotNil(iniFile)
XCTAssertGreaterThan(iniFile.extensions.count, 0)
#expect(iniFile.has(key: "error_reporting"))
#expect(iniFile.has(key: "display_errors"))
#expect(false == iniFile.has(key: "my_unknown_key"))
}
func test_can_check_key_existence() throws {
@Test func test_can_check_key_value() throws {
let iniFile = PhpConfigurationFile.from(filePath: Self.phpIniFileUrl.path)!
XCTAssertTrue(iniFile.has(key: "error_reporting"))
XCTAssertTrue(iniFile.has(key: "display_errors"))
XCTAssertFalse(iniFile.has(key: "my_unknown_key"))
#expect(iniFile.get(for: "error_reporting") != nil)
#expect(iniFile.get(for: "error_reporting") == "E_ALL")
#expect(iniFile.get(for: "display_errors") != nil)
#expect(iniFile.get(for: "display_errors") == "On")
}
func test_can_check_key_value() throws {
let iniFile = PhpConfigurationFile.from(filePath: Self.phpIniFileUrl.path)!
XCTAssertNotNil(iniFile.get(for: "error_reporting"))
XCTAssert(iniFile.get(for: "error_reporting") == "E_ALL")
XCTAssertNotNil(iniFile.get(for: "display_errors"))
XCTAssert(iniFile.get(for: "display_errors") == "On")
}
func test_can_customize_configuration_value() throws {
@Test func test_can_customize_configuration_value() throws {
let destination = Utility
.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
@@ -48,15 +48,15 @@ class PhpConfigurationFileTest: XCTestCase {
.from(filePath: destination.path)!
// 0. Verify the original value
XCTAssertEqual(configurationFile.get(for: "error_reporting"), "E_ALL")
#expect(configurationFile.get(for: "error_reporting") == "E_ALL")
// 1. Change the value
try! configurationFile.replace(
key: "error_reporting",
value: "E_ALL & ~E_DEPRECATED & ~E_STRICT"
)
XCTAssertEqual(
configurationFile.get(for: "error_reporting"),
#expect(
configurationFile.get(for: "error_reporting") ==
"E_ALL & ~E_DEPRECATED & ~E_STRICT"
)
@@ -65,20 +65,14 @@ class PhpConfigurationFileTest: XCTestCase {
key: "error_reporting",
value: "error_reporting"
)
XCTAssertEqual(
configurationFile.get(for: "error_reporting"),
"error_reporting"
)
#expect(configurationFile.get(for: "error_reporting") == "error_reporting")
// 3. Verify subsequent saves weren't broken
try! configurationFile.replace(
key: "error_reporting",
value: "E_ALL"
)
XCTAssertEqual(
configurationFile.get(for: "error_reporting"),
"E_ALL"
)
#expect(configurationFile.get(for: "error_reporting") == "E_ALL")
}
}

View File

@@ -6,53 +6,54 @@
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import XCTest
import Testing
import Foundation
class HomebrewPackageTest: XCTestCase {
struct HomebrewPackageTest {
// - MARK: SYNTHETIC TESTS
static var jsonBrewFile: URL {
return Bundle(for: Self.self)
return TestBundle
.url(forResource: "brew-formula", withExtension: "json")!
}
func test_can_load_extension_json() throws {
static var jsonBrewServicesFile: URL {
return TestBundle
.url(forResource: "brew-services", withExtension: "json")!
}
@Test func test_can_load_extension_json() throws {
let json = try! String(contentsOf: Self.jsonBrewFile, encoding: .utf8)
let package = try! JSONDecoder().decode(
[HomebrewPackage].self, from: json.data(using: .utf8)!
).first!
XCTAssertEqual(package.full_name, "php")
XCTAssertEqual(package.aliases.first!, "php@8.4")
XCTAssertEqual(package.installed.contains(where: { installed in
#expect(package.full_name == "php")
#expect(package.aliases.first! == "php@8.4")
#expect(package.installed.contains(where: { installed in
installed.version.starts(with: "8.4")
}), true)
}) == true)
}
static var jsonBrewServicesFile: URL {
return Bundle(for: Self.self)
.url(forResource: "brew-services", withExtension: "json")!
}
func test_can_parse_services_json() throws {
@Test func test_can_parse_services_json() throws {
let json = try! String(contentsOf: Self.jsonBrewServicesFile, encoding: .utf8)
let services = try! JSONDecoder().decode(
[HomebrewService].self, from: json.data(using: .utf8)!
)
XCTAssertGreaterThan(services.count, 0)
XCTAssertEqual(services.first?.name, "dnsmasq")
XCTAssertEqual(services.first?.service_name, "homebrew.mxcl.dnsmasq")
#expect(!services.isEmpty)
#expect(services.first?.name == "dnsmasq")
#expect(services.first?.service_name == "homebrew.mxcl.dnsmasq")
}
/*
// - MARK: LIVE TESTS
/// This test requires that you have a valid Homebrew installation set up,
/// and requires the Valet services to be installed: php, nginx and dnsmasq.
/// If this test fails, there is an issue with your Homebrew installation
/// or the JSON API of the Homebrew output may have changed.
@Test(.disabled("Uses system command; enable at your own risk"))
func test_can_parse_services_json_from_cli_output() async throws {
ActiveShell.useSystem()
@@ -65,17 +66,19 @@ class HomebrewPackageTest: XCTestCase {
return ["php", "nginx", "dnsmasq"].contains(service.name)
})
XCTAssertTrue(services.contains(where: {$0.name == "php"}))
XCTAssertTrue(services.contains(where: {$0.name == "nginx"}))
XCTAssertTrue(services.contains(where: {$0.name == "dnsmasq"}))
XCTAssertEqual(services.count, 3)
#expect(services.contains(where: {$0.name == "php"}))
#expect(services.contains(where: {$0.name == "nginx"}))
#expect(services.contains(where: {$0.name == "dnsmasq"}))
#expect(services.count == 3)
}
/// This test requires that you have a valid Homebrew installation set up,
/// and requires the `php` formula to be installed.
/// If this test fails, there is an issue with your Homebrew installation
/// or the JSON API of the Homebrew output may have changed.
@Test(.disabled("Uses system command; enable at your own risk"))
func test_can_load_extension_json_from_cli_output() async throws {
ActiveShell.useSystem()
let package = try! JSONDecoder().decode(
@@ -83,7 +86,6 @@ class HomebrewPackageTest: XCTestCase {
from: await Shell.pipe("\(Paths.brew) info php --json").out.data(using: .utf8)!
).first!
XCTAssertTrue(package.name == "php")
#expect(package.full_name == "php")
}
*/
}

View File

@@ -0,0 +1,70 @@
//
// NginxConfigurationTest.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 29/11/2021.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Testing
import Foundation
struct NginxConfigurationTest {
// MARK: - Test Files
static var regularUrl: URL {
TestBundle.url(forResource: "nginx-site", withExtension: "test")!
}
static var isolatedUrl: URL {
TestBundle.url(forResource: "nginx-site-isolated", withExtension: "test")!
}
static var proxyUrl: URL {
TestBundle.url(forResource: "nginx-proxy", withExtension: "test")!
}
static var secureProxyUrl: URL {
TestBundle.url(forResource: "nginx-secure-proxy", withExtension: "test")!
}
static var customTldProxyUrl: URL {
TestBundle.url(forResource: "nginx-secure-proxy-custom-tld", withExtension: "test")!
}
// MARK: - Tests
@Test func test_can_determine_site_name_and_tld() throws {
#expect("nginx-site" == NginxConfigurationFile.from(filePath: Self.regularUrl.path)?.domain)
#expect("test" == NginxConfigurationFile.from(filePath: Self.regularUrl.path)?.tld)
}
@Test func test_can_determine_isolation() throws {
#expect(nil == NginxConfigurationFile.from(filePath: Self.regularUrl.path)?.isolatedVersion)
#expect("8.1" == NginxConfigurationFile.from(filePath: Self.isolatedUrl.path)?.isolatedVersion)
}
@Test func test_can_determine_proxy() throws {
let proxied = NginxConfigurationFile.from(filePath: Self.proxyUrl.path)!
#expect(proxied.contents.contains("# valet stub: proxy.valet.conf"))
#expect("http://127.0.0.1:90" == proxied.proxy)
let normal = NginxConfigurationFile.from(filePath: Self.regularUrl.path)!
#expect(false == normal.contents.contains("# valet stub: proxy.valet.conf"))
#expect(nil == normal.proxy)
}
@Test func test_can_determine_secured_proxy() throws {
let proxied = NginxConfigurationFile.from(filePath: Self.secureProxyUrl.path)!
#expect(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
#expect("http://127.0.0.1:90" == proxied.proxy)
}
@Test func test_can_determine_proxy_with_custom_tld() throws {
let proxied = NginxConfigurationFile.from(filePath: Self.customTldProxyUrl.path)!
#expect(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
#expect("http://localhost:8080" == proxied.proxy)
}
}

View File

@@ -0,0 +1,71 @@
//
// ExtensionParserTest.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 13/02/2021.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Testing
import Foundation
struct PhpExtensionTest {
static var phpIniFileUrl: URL {
return TestBundle.url(forResource: "php", withExtension: "ini")!
}
@Test func test_can_load_extension() throws {
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
#expect(!extensions.isEmpty)
}
@Test func test_extension_name_is_correct() throws {
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
let extensionNames = extensions.map { (ext) -> String in
return ext.name
}
// These 6 should be found
#expect(extensionNames.contains("xdebug"))
#expect(extensionNames.contains("imagick"))
#expect(extensionNames.contains("sodium-next"))
#expect(extensionNames.contains("opcache"))
#expect(extensionNames.contains("yaml"))
#expect(extensionNames.contains("custom"))
#expect(extensionNames.contains("fake") == false)
#expect(extensionNames.contains("nice") == false)
}
@Test func test_extension_status_is_correct() throws {
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
// xdebug should be enabled
#expect(extensions[0].enabled == true)
// imagick should be disabled
#expect(extensions[1].enabled == false)
}
@Test func test_toggle_works_as_expected() async throws {
let destination = Utility.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
let extensions = PhpExtension.from(filePath: destination.path)
#expect(extensions.count == 6)
// Try to disable xdebug (should be detected first)!
let xdebug = extensions.first!
#expect(xdebug.name == "xdebug")
#expect(xdebug.enabled == true)
await xdebug.toggle()
#expect(xdebug.enabled == false)
// Check if the file contains the appropriate data
let file = try! String(contentsOf: destination, encoding: .utf8)
#expect(file.contains("; zend_extension=\"xdebug.so\""))
// Make sure if we load the data again, it's disabled
#expect(PhpExtension.from(filePath: destination.path).first!.enabled == false)
}
}

View File

@@ -9,7 +9,6 @@
import Testing
import Foundation
@Suite("Parsers")
struct ValetConfigurationTest {
static var jsonConfigFileUrl: URL {
return TestBundle.url(
@@ -18,8 +17,7 @@ struct ValetConfigurationTest {
)!
}
@Test("Can load config file")
func can_load_config_file() throws {
@Test func can_load_config_file() throws {
let json = try? String(
contentsOf: Self.jsonConfigFileUrl,
encoding: .utf8
@@ -37,5 +35,4 @@ struct ValetConfigurationTest {
#expect(config.defaultSite == "/Users/username/default-site")
#expect(config.loopback == "127.0.0.1")
}
}

View File

@@ -0,0 +1,45 @@
//
// ValetRcTest.swift
// Unit Tests
//
// Created by Nico Verbruggen on 20/01/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Testing
import Foundation
struct ValetRcTest {
// MARK: - Test Files
static var validPath: URL {
return TestBundle.url(forResource: "valetrc", withExtension: "valid")!
}
static var brokenPath: URL {
return TestBundle.url(forResource: "valetrc", withExtension: "broken")!
}
// MARK: - Tests
@Test func test_can_extract_fields_from_valet_rc_file() throws {
let fakeFile = RCFile.fromPath("/Users/fake/file.rc")
#expect(nil == fakeFile)
// Can parse the file
let validFile = RCFile.fromPath(ValetRcTest.validPath.path)
#expect(nil != validFile)
let fields = validFile!.fields
// Correctly parses and trims (and omits double quotes) per line
#expect(fields["PHP"] == "php@8.2")
#expect(fields["OTHER"] == "thing")
#expect(fields["PHPMON_WATCH"] == "true")
#expect(fields["SYNTAX"] == "variable")
// Ignores entries prefixed with #
#expect(!fields.keys.contains("#PHP"))
// Ignores invalid lines
#expect(!fields.keys.contains("OOF"))
}
}