diff --git a/exercises/practice/clock/.meta/template.swift b/exercises/practice/clock/.meta/template.swift index b8d0b74c1..05b7728c5 100644 --- a/exercises/practice/clock/.meta/template.swift +++ b/exercises/practice/clock/.meta/template.swift @@ -1,31 +1,33 @@ -import XCTest +import Testing +import Foundation @testable import {{exercise|camelCase}} -class {{exercise|camelCase}}Tests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct {{exercise|camelCase}}Tests { {% outer: for case in cases %} {%- for subCases in case.cases %} {%- if forloop.outer.first and forloop.first %} - func test{{subCases.description |camelCase }}() { + @Test("{{subCases.description}}") {%- else %} - func test{{subCases.description |camelCase }}() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("{{subCases.description}}", .enabled(if: RUNALL)) {%- endif %} + func test{{subCases.description |camelCase }}() { {%- if subCases.property == "create" %} - XCTAssertEqual(Clock(hours: {{subCases.input.hour}}, minutes: {{subCases.input.minute}}).description, "{{subCases.expected}}") + #expect(Clock(hours: {{subCases.input.hour}}, minutes: {{subCases.input.minute}}).description == "{{subCases.expected}}") {%- elif subCases.property == "add"%} let clock = Clock(hours: {{subCases.input.hour}}, minutes: {{subCases.input.minute}}).add(minutes: {{subCases.input.value}}) - XCTAssertEqual(clock.description, "{{subCases.expected}}") + #expect(clock.description == "{{subCases.expected}}") {%- elif subCases.property == "subtract" %} let clock = Clock(hours: {{subCases.input.hour}}, minutes: {{subCases.input.minute}}).subtract(minutes: {{subCases.input.value}}) - XCTAssertEqual(clock.description, "{{subCases.expected}}") + #expect(clock.description == "{{subCases.expected}}") {%- elif subCases.property == "equal" %} let clock1 = Clock(hours: {{subCases.input.clock1.hour}}, minutes: {{subCases.input.clock1.minute}}) let clock2 = Clock(hours: {{subCases.input.clock2.hour}}, minutes: {{subCases.input.clock2.minute}}) {%- if subCases.expected %} - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) {%- else %} - XCTAssertNotEqual(clock1, clock2) + #expect(clock1 != clock2) {%- endif %} {%- endif %} } diff --git a/exercises/practice/clock/Package.swift b/exercises/practice/clock/Package.swift index 764caf6f1..58991f173 100644 --- a/exercises/practice/clock/Package.swift +++ b/exercises/practice/clock/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:6.0 import PackageDescription diff --git a/exercises/practice/clock/Tests/ClockTests/ClockTests.swift b/exercises/practice/clock/Tests/ClockTests/ClockTests.swift index 5d2036de2..3b7fa6169 100644 --- a/exercises/practice/clock/Tests/ClockTests/ClockTests.swift +++ b/exercises/practice/clock/Tests/ClockTests/ClockTests.swift @@ -1,314 +1,317 @@ -import XCTest +import Foundation +import Testing @testable import Clock -class ClockTests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +@Suite struct ClockTests { + + @Test("on the hour") func testOnTheHour() { - XCTAssertEqual(Clock(hours: 8, minutes: 0).description, "08:00") + #expect(Clock(hours: 8, minutes: 0).description == "08:00") } - func testPastTheHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 11, minutes: 9).description, "11:09") + @Test("past the hour", .enabled(if: RUNALL)) + func testPastTheHour() { + #expect(Clock(hours: 11, minutes: 9).description == "11:09") } - func testMidnightIsZeroHours() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 24, minutes: 0).description, "00:00") + @Test("midnight is zero hours", .enabled(if: RUNALL)) + func testMidnightIsZeroHours() { + #expect(Clock(hours: 24, minutes: 0).description == "00:00") } - func testHourRollsOver() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 25, minutes: 0).description, "01:00") + @Test("hour rolls over", .enabled(if: RUNALL)) + func testHourRollsOver() { + #expect(Clock(hours: 25, minutes: 0).description == "01:00") } - func testHourRollsOverContinuously() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 100, minutes: 0).description, "04:00") + @Test("hour rolls over continuously", .enabled(if: RUNALL)) + func testHourRollsOverContinuously() { + #expect(Clock(hours: 100, minutes: 0).description == "04:00") } - func testSixtyMinutesIsNextHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 1, minutes: 60).description, "02:00") + @Test("sixty minutes is next hour", .enabled(if: RUNALL)) + func testSixtyMinutesIsNextHour() { + #expect(Clock(hours: 1, minutes: 60).description == "02:00") } - func testMinutesRollOver() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 0, minutes: 160).description, "02:40") + @Test("minutes roll over", .enabled(if: RUNALL)) + func testMinutesRollOver() { + #expect(Clock(hours: 0, minutes: 160).description == "02:40") } - func testMinutesRollOverContinuously() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 0, minutes: 1723).description, "04:43") + @Test("minutes roll over continuously", .enabled(if: RUNALL)) + func testMinutesRollOverContinuously() { + #expect(Clock(hours: 0, minutes: 1723).description == "04:43") } - func testHourAndMinutesRollOver() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 25, minutes: 160).description, "03:40") + @Test("hour and minutes roll over", .enabled(if: RUNALL)) + func testHourAndMinutesRollOver() { + #expect(Clock(hours: 25, minutes: 160).description == "03:40") } - func testHourAndMinutesRollOverContinuously() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 201, minutes: 3001).description, "11:01") + @Test("hour and minutes roll over continuously", .enabled(if: RUNALL)) + func testHourAndMinutesRollOverContinuously() { + #expect(Clock(hours: 201, minutes: 3001).description == "11:01") } - func testHourAndMinutesRollOverToExactlyMidnight() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 72, minutes: 8640).description, "00:00") + @Test("hour and minutes roll over to exactly midnight", .enabled(if: RUNALL)) + func testHourAndMinutesRollOverToExactlyMidnight() { + #expect(Clock(hours: 72, minutes: 8640).description == "00:00") } - func testNegativeHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: -1, minutes: 15).description, "23:15") + @Test("negative hour", .enabled(if: RUNALL)) + func testNegativeHour() { + #expect(Clock(hours: -1, minutes: 15).description == "23:15") } - func testNegativeHourRollsOver() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: -25, minutes: 0).description, "23:00") + @Test("negative hour rolls over", .enabled(if: RUNALL)) + func testNegativeHourRollsOver() { + #expect(Clock(hours: -25, minutes: 0).description == "23:00") } - func testNegativeHourRollsOverContinuously() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: -91, minutes: 0).description, "05:00") + @Test("negative hour rolls over continuously", .enabled(if: RUNALL)) + func testNegativeHourRollsOverContinuously() { + #expect(Clock(hours: -91, minutes: 0).description == "05:00") } - func testNegativeMinutes() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 1, minutes: -40).description, "00:20") + @Test("negative minutes", .enabled(if: RUNALL)) + func testNegativeMinutes() { + #expect(Clock(hours: 1, minutes: -40).description == "00:20") } - func testNegativeMinutesRollOver() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 1, minutes: -160).description, "22:20") + @Test("negative minutes roll over", .enabled(if: RUNALL)) + func testNegativeMinutesRollOver() { + #expect(Clock(hours: 1, minutes: -160).description == "22:20") } - func testNegativeMinutesRollOverContinuously() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 1, minutes: -4820).description, "16:40") + @Test("negative minutes roll over continuously", .enabled(if: RUNALL)) + func testNegativeMinutesRollOverContinuously() { + #expect(Clock(hours: 1, minutes: -4820).description == "16:40") } - func testNegativeSixtyMinutesIsPreviousHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: 2, minutes: -60).description, "01:00") + @Test("negative sixty minutes is previous hour", .enabled(if: RUNALL)) + func testNegativeSixtyMinutesIsPreviousHour() { + #expect(Clock(hours: 2, minutes: -60).description == "01:00") } - func testNegativeHourAndMinutesBothRollOver() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: -25, minutes: -160).description, "20:20") + @Test("negative hour and minutes both roll over", .enabled(if: RUNALL)) + func testNegativeHourAndMinutesBothRollOver() { + #expect(Clock(hours: -25, minutes: -160).description == "20:20") } - func testNegativeHourAndMinutesBothRollOverContinuously() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(Clock(hours: -121, minutes: -5810).description, "22:10") + @Test("negative hour and minutes both roll over continuously", .enabled(if: RUNALL)) + func testNegativeHourAndMinutesBothRollOverContinuously() { + #expect(Clock(hours: -121, minutes: -5810).description == "22:10") } - func testAddMinutes() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add minutes", .enabled(if: RUNALL)) + func testAddMinutes() { let clock = Clock(hours: 10, minutes: 0).add(minutes: 3) - XCTAssertEqual(clock.description, "10:03") + #expect(clock.description == "10:03") } - func testAddNoMinutes() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add no minutes", .enabled(if: RUNALL)) + func testAddNoMinutes() { let clock = Clock(hours: 6, minutes: 41).add(minutes: 0) - XCTAssertEqual(clock.description, "06:41") + #expect(clock.description == "06:41") } - func testAddToNextHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add to next hour", .enabled(if: RUNALL)) + func testAddToNextHour() { let clock = Clock(hours: 0, minutes: 45).add(minutes: 40) - XCTAssertEqual(clock.description, "01:25") + #expect(clock.description == "01:25") } - func testAddMoreThanOneHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add more than one hour", .enabled(if: RUNALL)) + func testAddMoreThanOneHour() { let clock = Clock(hours: 10, minutes: 0).add(minutes: 61) - XCTAssertEqual(clock.description, "11:01") + #expect(clock.description == "11:01") } - func testAddMoreThanTwoHoursWithCarry() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add more than two hours with carry", .enabled(if: RUNALL)) + func testAddMoreThanTwoHoursWithCarry() { let clock = Clock(hours: 0, minutes: 45).add(minutes: 160) - XCTAssertEqual(clock.description, "03:25") + #expect(clock.description == "03:25") } - func testAddAcrossMidnight() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add across midnight", .enabled(if: RUNALL)) + func testAddAcrossMidnight() { let clock = Clock(hours: 23, minutes: 59).add(minutes: 2) - XCTAssertEqual(clock.description, "00:01") + #expect(clock.description == "00:01") } - func testAddMoreThanOneDay1500Min25Hrs() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add more than one day (1500 min = 25 hrs)", .enabled(if: RUNALL)) + func testAddMoreThanOneDay1500Min25Hrs() { let clock = Clock(hours: 5, minutes: 32).add(minutes: 1500) - XCTAssertEqual(clock.description, "06:32") + #expect(clock.description == "06:32") } - func testAddMoreThanTwoDays() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("add more than two days", .enabled(if: RUNALL)) + func testAddMoreThanTwoDays() { let clock = Clock(hours: 1, minutes: 1).add(minutes: 3500) - XCTAssertEqual(clock.description, "11:21") + #expect(clock.description == "11:21") } - func testSubtractMinutes() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract minutes", .enabled(if: RUNALL)) + func testSubtractMinutes() { let clock = Clock(hours: 10, minutes: 3).subtract(minutes: 3) - XCTAssertEqual(clock.description, "10:00") + #expect(clock.description == "10:00") } - func testSubtractToPreviousHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract to previous hour", .enabled(if: RUNALL)) + func testSubtractToPreviousHour() { let clock = Clock(hours: 10, minutes: 3).subtract(minutes: 30) - XCTAssertEqual(clock.description, "09:33") + #expect(clock.description == "09:33") } - func testSubtractMoreThanAnHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract more than an hour", .enabled(if: RUNALL)) + func testSubtractMoreThanAnHour() { let clock = Clock(hours: 10, minutes: 3).subtract(minutes: 70) - XCTAssertEqual(clock.description, "08:53") + #expect(clock.description == "08:53") } - func testSubtractAcrossMidnight() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract across midnight", .enabled(if: RUNALL)) + func testSubtractAcrossMidnight() { let clock = Clock(hours: 0, minutes: 3).subtract(minutes: 4) - XCTAssertEqual(clock.description, "23:59") + #expect(clock.description == "23:59") } - func testSubtractMoreThanTwoHours() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract more than two hours", .enabled(if: RUNALL)) + func testSubtractMoreThanTwoHours() { let clock = Clock(hours: 0, minutes: 0).subtract(minutes: 160) - XCTAssertEqual(clock.description, "21:20") + #expect(clock.description == "21:20") } - func testSubtractMoreThanTwoHoursWithBorrow() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract more than two hours with borrow", .enabled(if: RUNALL)) + func testSubtractMoreThanTwoHoursWithBorrow() { let clock = Clock(hours: 6, minutes: 15).subtract(minutes: 160) - XCTAssertEqual(clock.description, "03:35") + #expect(clock.description == "03:35") } - func testSubtractMoreThanOneDay1500Min25Hrs() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract more than one day (1500 min = 25 hrs)", .enabled(if: RUNALL)) + func testSubtractMoreThanOneDay1500Min25Hrs() { let clock = Clock(hours: 5, minutes: 32).subtract(minutes: 1500) - XCTAssertEqual(clock.description, "04:32") + #expect(clock.description == "04:32") } - func testSubtractMoreThanTwoDays() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("subtract more than two days", .enabled(if: RUNALL)) + func testSubtractMoreThanTwoDays() { let clock = Clock(hours: 2, minutes: 20).subtract(minutes: 3000) - XCTAssertEqual(clock.description, "00:20") + #expect(clock.description == "00:20") } - func testClocksWithSameTime() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with same time", .enabled(if: RUNALL)) + func testClocksWithSameTime() { let clock1 = Clock(hours: 15, minutes: 37) let clock2 = Clock(hours: 15, minutes: 37) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksAMinuteApart() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks a minute apart", .enabled(if: RUNALL)) + func testClocksAMinuteApart() { let clock1 = Clock(hours: 15, minutes: 36) let clock2 = Clock(hours: 15, minutes: 37) - XCTAssertNotEqual(clock1, clock2) + #expect(clock1 != clock2) } - func testClocksAnHourApart() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks an hour apart", .enabled(if: RUNALL)) + func testClocksAnHourApart() { let clock1 = Clock(hours: 14, minutes: 37) let clock2 = Clock(hours: 15, minutes: 37) - XCTAssertNotEqual(clock1, clock2) + #expect(clock1 != clock2) } - func testClocksWithHourOverflow() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with hour overflow", .enabled(if: RUNALL)) + func testClocksWithHourOverflow() { let clock1 = Clock(hours: 10, minutes: 37) let clock2 = Clock(hours: 34, minutes: 37) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithHourOverflowBySeveralDays() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with hour overflow by several days", .enabled(if: RUNALL)) + func testClocksWithHourOverflowBySeveralDays() { let clock1 = Clock(hours: 3, minutes: 11) let clock2 = Clock(hours: 99, minutes: 11) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeHour() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative hour", .enabled(if: RUNALL)) + func testClocksWithNegativeHour() { let clock1 = Clock(hours: 22, minutes: 40) let clock2 = Clock(hours: -2, minutes: 40) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeHourThatWraps() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative hour that wraps", .enabled(if: RUNALL)) + func testClocksWithNegativeHourThatWraps() { let clock1 = Clock(hours: 17, minutes: 3) let clock2 = Clock(hours: -31, minutes: 3) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeHourThatWrapsMultipleTimes() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative hour that wraps multiple times", .enabled(if: RUNALL)) + func testClocksWithNegativeHourThatWrapsMultipleTimes() { let clock1 = Clock(hours: 13, minutes: 49) let clock2 = Clock(hours: -83, minutes: 49) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithMinuteOverflow() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with minute overflow", .enabled(if: RUNALL)) + func testClocksWithMinuteOverflow() { let clock1 = Clock(hours: 0, minutes: 1) let clock2 = Clock(hours: 0, minutes: 1441) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithMinuteOverflowBySeveralDays() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with minute overflow by several days", .enabled(if: RUNALL)) + func testClocksWithMinuteOverflowBySeveralDays() { let clock1 = Clock(hours: 2, minutes: 2) let clock2 = Clock(hours: 2, minutes: 4322) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeMinute() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative minute", .enabled(if: RUNALL)) + func testClocksWithNegativeMinute() { let clock1 = Clock(hours: 2, minutes: 40) let clock2 = Clock(hours: 3, minutes: -20) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeMinuteThatWraps() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative minute that wraps", .enabled(if: RUNALL)) + func testClocksWithNegativeMinuteThatWraps() { let clock1 = Clock(hours: 4, minutes: 10) let clock2 = Clock(hours: 5, minutes: -1490) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeMinuteThatWrapsMultipleTimes() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative minute that wraps multiple times", .enabled(if: RUNALL)) + func testClocksWithNegativeMinuteThatWrapsMultipleTimes() { let clock1 = Clock(hours: 6, minutes: 15) let clock2 = Clock(hours: 6, minutes: -4305) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeHoursAndMinutes() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative hours and minutes", .enabled(if: RUNALL)) + func testClocksWithNegativeHoursAndMinutes() { let clock1 = Clock(hours: 7, minutes: 32) let clock2 = Clock(hours: -12, minutes: -268) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testClocksWithNegativeHoursAndMinutesThatWrap() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("clocks with negative hours and minutes that wrap", .enabled(if: RUNALL)) + func testClocksWithNegativeHoursAndMinutesThatWrap() { let clock1 = Clock(hours: 18, minutes: 7) let clock2 = Clock(hours: -54, minutes: -11513) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } - func testFullClockAndZeroedClock() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("full clock and zeroed clock", .enabled(if: RUNALL)) + func testFullClockAndZeroedClock() { let clock1 = Clock(hours: 24, minutes: 0) let clock2 = Clock(hours: 0, minutes: 0) - XCTAssertEqual(clock1, clock2) + #expect(clock1 == clock2) } } diff --git a/exercises/practice/collatz-conjecture/.docs/instructions.md b/exercises/practice/collatz-conjecture/.docs/instructions.md index ba060483e..af332a810 100644 --- a/exercises/practice/collatz-conjecture/.docs/instructions.md +++ b/exercises/practice/collatz-conjecture/.docs/instructions.md @@ -1,29 +1,3 @@ # Instructions -The Collatz Conjecture or 3x+1 problem can be summarized as follows: - -Take any positive integer n. -If n is even, divide n by 2 to get n / 2. -If n is odd, multiply n by 3 and add 1 to get 3n + 1. -Repeat the process indefinitely. -The conjecture states that no matter which number you start with, you will always reach 1 eventually. - -Given a number n, return the number of steps required to reach 1. - -## Examples - -Starting with n = 12, the steps would be as follows: - -0. 12 -1. 6 -2. 3 -3. 10 -4. 5 -5. 16 -6. 8 -7. 4 -8. 2 -9. 1 - -Resulting in 9 steps. -So for input n = 12, the return value would be 9. +Given a positive integer, return the number of steps it takes to reach 1 according to the rules of the Collatz Conjecture. diff --git a/exercises/practice/collatz-conjecture/.docs/introduction.md b/exercises/practice/collatz-conjecture/.docs/introduction.md new file mode 100644 index 000000000..c35bdeb67 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.docs/introduction.md @@ -0,0 +1,28 @@ +# Introduction + +One evening, you stumbled upon an old notebook filled with cryptic scribbles, as though someone had been obsessively chasing an idea. +On one page, a single question stood out: **Can every number find its way to 1?** +It was tied to something called the **Collatz Conjecture**, a puzzle that has baffled thinkers for decades. + +The rules were deceptively simple. +Pick any positive integer. + +- If it's even, divide it by 2. +- If it's odd, multiply it by 3 and add 1. + +Then, repeat these steps with the result, continuing indefinitely. + +Curious, you picked number 12 to test and began the journey: + +12 ➜ 6 ➜ 3 ➜ 10 ➜ 5 ➜ 16 ➜ 8 ➜ 4 ➜ 2 ➜ 1 + +Counting from the second number (6), it took 9 steps to reach 1, and each time the rules repeated, the number kept changing. +At first, the sequence seemed unpredictable — jumping up, down, and all over. +Yet, the conjecture claims that no matter the starting number, we'll always end at 1. + +It was fascinating, but also puzzling. +Why does this always seem to work? +Could there be a number where the process breaks down, looping forever or escaping into infinity? +The notebook suggested solving this could reveal something profound — and with it, fame, [fortune][collatz-prize], and a place in history awaits whoever could unlock its secrets. + +[collatz-prize]: https://mathprize.net/posts/collatz-conjecture/ diff --git a/exercises/practice/collatz-conjecture/.meta/config.json b/exercises/practice/collatz-conjecture/.meta/config.json index 696e4d198..204a7ad3a 100644 --- a/exercises/practice/collatz-conjecture/.meta/config.json +++ b/exercises/practice/collatz-conjecture/.meta/config.json @@ -21,6 +21,6 @@ ] }, "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", - "source": "An unsolved problem in mathematics named after mathematician Lothar Collatz", - "source_url": "https://en.wikipedia.org/wiki/3x_%2B_1_problem" + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Collatz_conjecture" } diff --git a/exercises/practice/collatz-conjecture/.meta/template.swift b/exercises/practice/collatz-conjecture/.meta/template.swift index d9aec1211..df038d482 100644 --- a/exercises/practice/collatz-conjecture/.meta/template.swift +++ b/exercises/practice/collatz-conjecture/.meta/template.swift @@ -1,19 +1,21 @@ -import XCTest +import Testing +import Foundation @testable import {{exercise|camelCase}} -class {{exercise|camelCase}}Tests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct {{exercise|camelCase}}Tests { {% for case in cases %} - {% if forloop.first -%} + {% if forloop.first -%} + @Test("{{case.description}}") + {% else -%} + @Test("{{case.description}}", .enabled(if: RUNALL)) + {% endif -%} func test{{case.description |camelCase }}() { - {% else -%} - func test{{case.description |camelCase }}() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - {% endif -%} {%- ifnot case.expected.error -%} - XCTAssertEqual({{case.expected}}, try! CollatzConjecture.steps({{case.input.number}})) - {%- else -%} - XCTAssertThrowsError(try CollatzConjecture.steps({{case.input.number}})) + #expect(try! CollatzConjecture.steps({{case.input.number}}) == {{case.expected}}) + {%- else %} + #expect(throws: (any Error).self){try CollatzConjecture.steps({{case.input.number}})} {%- endif -%} } {% endfor -%} diff --git a/exercises/practice/collatz-conjecture/Package.swift b/exercises/practice/collatz-conjecture/Package.swift index c3e84fa1b..a03996ab9 100644 --- a/exercises/practice/collatz-conjecture/Package.swift +++ b/exercises/practice/collatz-conjecture/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:6.0 import PackageDescription diff --git a/exercises/practice/collatz-conjecture/Tests/CollatzConjectureTests/CollatzConjectureTests.swift b/exercises/practice/collatz-conjecture/Tests/CollatzConjectureTests/CollatzConjectureTests.swift index 1d2d408f3..8523ddce9 100644 --- a/exercises/practice/collatz-conjecture/Tests/CollatzConjectureTests/CollatzConjectureTests.swift +++ b/exercises/practice/collatz-conjecture/Tests/CollatzConjectureTests/CollatzConjectureTests.swift @@ -1,36 +1,33 @@ -import XCTest +import Foundation +import Testing @testable import CollatzConjecture -class CollatzConjectureTests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false - func testZeroStepsForOne() { - XCTAssertEqual(0, try! CollatzConjecture.steps(1)) - } +@Suite struct CollatzConjectureTests { - func testDivideIfEven() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(4, try! CollatzConjecture.steps(16)) - } + @Test("zero steps for one") + func testZeroStepsForOne() { #expect(try! CollatzConjecture.steps(1) == 0) } - func testEvenAndOddSteps() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(9, try! CollatzConjecture.steps(12)) - } + @Test("divide if even", .enabled(if: RUNALL)) + func testDivideIfEven() { #expect(try! CollatzConjecture.steps(16) == 4) } + + @Test("even and odd steps", .enabled(if: RUNALL)) + func testEvenAndOddSteps() { #expect(try! CollatzConjecture.steps(12) == 9) } - func testLargeNumberOfEvenAndOddSteps() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(152, try! CollatzConjecture.steps(1_000_000)) + @Test("large number of even and odd steps", .enabled(if: RUNALL)) + func testLargeNumberOfEvenAndOddSteps() { + #expect(try! CollatzConjecture.steps(1_000_000) == 152) } - func testZeroIsAnError() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertThrowsError(try CollatzConjecture.steps(0)) + @Test("zero is an error", .enabled(if: RUNALL)) + func testZeroIsAnError() { + #expect(throws: (any Error).self) { try CollatzConjecture.steps(0) } } - func testNegativeValueIsAnError() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertThrowsError(try CollatzConjecture.steps(-15)) + @Test("negative value is an error", .enabled(if: RUNALL)) + func testNegativeValueIsAnError() { + #expect(throws: (any Error).self) { try CollatzConjecture.steps(-15) } } } diff --git a/exercises/practice/crypto-square/.meta/template.swift b/exercises/practice/crypto-square/.meta/template.swift index 7977ab723..a8149d1e1 100644 --- a/exercises/practice/crypto-square/.meta/template.swift +++ b/exercises/practice/crypto-square/.meta/template.swift @@ -1,16 +1,18 @@ -import XCTest +import Testing +import Foundation @testable import {{exercise|camelCase}} -class {{exercise|camelCase}}Tests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct {{exercise|camelCase}}Tests { {% for case in cases %} {% if forloop.first -%} - func test{{case.description |camelCase }}() { + @Test("{{case.description}}") {% else -%} - func test{{case.description |camelCase }}() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test + @Test("{{case.description}}", .enabled(if: RUNALL)) {% endif -%} - XCTAssertEqual(cryptoSquare(text: "{{case.input.plaintext}}"), "{{case.expected}}") + func test{{case.description |camelCase }}() { + #expect(cryptoSquare(text: "{{case.input.plaintext}}") == "{{case.expected}}") } {% endfor -%} } diff --git a/exercises/practice/crypto-square/Package.swift b/exercises/practice/crypto-square/Package.swift index 2bb275b6a..0f97a734d 100644 --- a/exercises/practice/crypto-square/Package.swift +++ b/exercises/practice/crypto-square/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:6.0 import PackageDescription diff --git a/exercises/practice/crypto-square/Tests/CryptoSquareTests/CryptoSquareTests.swift b/exercises/practice/crypto-square/Tests/CryptoSquareTests/CryptoSquareTests.swift index 07449ac54..2a8e4d06e 100644 --- a/exercises/practice/crypto-square/Tests/CryptoSquareTests/CryptoSquareTests.swift +++ b/exercises/practice/crypto-square/Tests/CryptoSquareTests/CryptoSquareTests.swift @@ -1,48 +1,55 @@ -import XCTest +import Foundation +import Testing @testable import CryptoSquare -class CryptoSquareTests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +@Suite struct CryptoSquareTests { + + @Test("empty plaintext results in an empty ciphertext") func testEmptyPlaintextResultsInAnEmptyCiphertext() { - XCTAssertEqual(cryptoSquare(text: ""), "") + #expect(cryptoSquare(text: "") == "") } - func testNormalizationResultsInEmptyPlaintext() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(cryptoSquare(text: "... --- ..."), "") + @Test("normalization results in empty plaintext", .enabled(if: RUNALL)) + func testNormalizationResultsInEmptyPlaintext() { + #expect(cryptoSquare(text: "... --- ...") == "") } - func testLowercase() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(cryptoSquare(text: "A"), "a") + @Test("Lowercase", .enabled(if: RUNALL)) + func testLowercase() { + #expect(cryptoSquare(text: "A") == "a") } - func testRemoveSpaces() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(cryptoSquare(text: " b "), "b") + @Test("Remove spaces", .enabled(if: RUNALL)) + func testRemoveSpaces() { + #expect(cryptoSquare(text: " b ") == "b") } - func testRemovePunctuation() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(cryptoSquare(text: "@1,%!"), "1") + @Test("Remove punctuation", .enabled(if: RUNALL)) + func testRemovePunctuation() { + #expect(cryptoSquare(text: "@1,%!") == "1") } - func test9CharacterPlaintextResultsIn3ChunksOf3Characters() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(cryptoSquare(text: "This is fun!"), "tsf hiu isn") + @Test("9 character plaintext results in 3 chunks of 3 characters", .enabled(if: RUNALL)) + func test9CharacterPlaintextResultsIn3ChunksOf3Characters() { + #expect(cryptoSquare(text: "This is fun!") == "tsf hiu isn") } - func test8CharacterPlaintextResultsIn3ChunksTheLastOneWithATrailingSpace() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(cryptoSquare(text: "Chill out."), "clu hlt io ") + @Test( + "8 character plaintext results in 3 chunks, the last one with a trailing space", + .enabled(if: RUNALL)) + func test8CharacterPlaintextResultsIn3ChunksTheLastOneWithATrailingSpace() { + #expect(cryptoSquare(text: "Chill out.") == "clu hlt io ") } - func test54CharacterPlaintextResultsIn7ChunksTheLastTwoWithTrailingSpaces() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual( - cryptoSquare(text: "If man was meant to stay on the ground, god would have given us roots."), - "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau ") + @Test( + "54 character plaintext results in 7 chunks, the last two with trailing spaces", + .enabled(if: RUNALL)) + func test54CharacterPlaintextResultsIn7ChunksTheLastTwoWithTrailingSpaces() { + #expect( + cryptoSquare(text: "If man was meant to stay on the ground, god would have given us roots.") + == "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau ") } } diff --git a/exercises/practice/darts/.meta/template.swift b/exercises/practice/darts/.meta/template.swift index 77fd528f3..0c5779beb 100644 --- a/exercises/practice/darts/.meta/template.swift +++ b/exercises/practice/darts/.meta/template.swift @@ -1,16 +1,18 @@ -import XCTest +import Testing +import Foundation @testable import {{exercise|camelCase}} -class {{exercise|camelCase}}Tests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct {{exercise|camelCase}}Tests { {% for case in cases %} - {% if forloop.first -%} + {% if forloop.first -%} + @Test("{{case.description}}") + {% else -%} + @Test("{{case.description}}", .enabled(if: RUNALL)) + {% endif -%} func test{{case.description |camelCase }}() { - {% else -%} - func test{{case.description |camelCase }}() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - {% endif -%} - XCTAssertEqual(dartScore(x: {{case.input.x | round:1 }}, y: {{case.input.y | round:1}}), {{case.expected}}) + #expect(dartScore(x: {{case.input.x | round:1 }}, y: {{case.input.y | round:1}}) == {{case.expected}}) } {% endfor -%} } diff --git a/exercises/practice/darts/Package.swift b/exercises/practice/darts/Package.swift index 1dd8e0708..ca53890d2 100644 --- a/exercises/practice/darts/Package.swift +++ b/exercises/practice/darts/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:6.0 import PackageDescription diff --git a/exercises/practice/darts/Tests/DartsTests/DartsTests.swift b/exercises/practice/darts/Tests/DartsTests/DartsTests.swift index 45491ab35..3730d5167 100644 --- a/exercises/practice/darts/Tests/DartsTests/DartsTests.swift +++ b/exercises/practice/darts/Tests/DartsTests/DartsTests.swift @@ -1,71 +1,74 @@ -import XCTest +import Foundation +import Testing @testable import Darts -class DartsTests: XCTestCase { - let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "true"]) ?? false +@Suite struct DartsTests { + + @Test("Missed target") func testMissedTarget() { - XCTAssertEqual(dartScore(x: -9, y: 9), 0) + #expect(dartScore(x: -9, y: 9) == 0) } - func testOnTheOuterCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: 0, y: 10), 1) + @Test("On the outer circle", .enabled(if: RUNALL)) + func testOnTheOuterCircle() { + #expect(dartScore(x: 0, y: 10) == 1) } - func testOnTheMiddleCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: -5, y: 0), 5) + @Test("On the middle circle", .enabled(if: RUNALL)) + func testOnTheMiddleCircle() { + #expect(dartScore(x: -5, y: 0) == 5) } - func testOnTheInnerCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: 0, y: -1), 10) + @Test("On the inner circle", .enabled(if: RUNALL)) + func testOnTheInnerCircle() { + #expect(dartScore(x: 0, y: -1) == 10) } - func testExactlyOnCenter() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: 0, y: 0), 10) + @Test("Exactly on center", .enabled(if: RUNALL)) + func testExactlyOnCenter() { + #expect(dartScore(x: 0, y: 0) == 10) } - func testNearTheCenter() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: -0.1, y: -0.1), 10) + @Test("Near the center", .enabled(if: RUNALL)) + func testNearTheCenter() { + #expect(dartScore(x: -0.1, y: -0.1) == 10) } - func testJustWithinTheInnerCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: 0.7, y: 0.7), 10) + @Test("Just within the inner circle", .enabled(if: RUNALL)) + func testJustWithinTheInnerCircle() { + #expect(dartScore(x: 0.7, y: 0.7) == 10) } - func testJustOutsideTheInnerCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: 0.8, y: -0.8), 5) + @Test("Just outside the inner circle", .enabled(if: RUNALL)) + func testJustOutsideTheInnerCircle() { + #expect(dartScore(x: 0.8, y: -0.8) == 5) } - func testJustWithinTheMiddleCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: -3.5, y: 3.5), 5) + @Test("Just within the middle circle", .enabled(if: RUNALL)) + func testJustWithinTheMiddleCircle() { + #expect(dartScore(x: -3.5, y: 3.5) == 5) } - func testJustOutsideTheMiddleCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: -3.6, y: -3.6), 1) + @Test("Just outside the middle circle", .enabled(if: RUNALL)) + func testJustOutsideTheMiddleCircle() { + #expect(dartScore(x: -3.6, y: -3.6) == 1) } - func testJustWithinTheOuterCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: -7, y: 7), 1) + @Test("Just within the outer circle", .enabled(if: RUNALL)) + func testJustWithinTheOuterCircle() { + #expect(dartScore(x: -7, y: 7) == 1) } - func testJustOutsideTheOuterCircle() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: 7.1, y: -7.1), 0) + @Test("Just outside the outer circle", .enabled(if: RUNALL)) + func testJustOutsideTheOuterCircle() { + #expect(dartScore(x: 7.1, y: -7.1) == 0) } - func testAsymmetricPositionBetweenTheInnerAndMiddleCircles() throws { - try XCTSkipIf(true && !runAll) // change true to false to run this test - XCTAssertEqual(dartScore(x: 0.5, y: -4), 5) + @Test("Asymmetric position between the inner and middle circles", .enabled(if: RUNALL)) + func testAsymmetricPositionBetweenTheInnerAndMiddleCircles() { + #expect(dartScore(x: 0.5, y: -4) == 5) } }