Created
February 11, 2026 10:05
-
-
Save musketyr/26142b71dfc353d600e216c73fd93ff6 to your computer and use it in GitHub Desktop.
Spock to JUnit 5 Migration Diff - sc185875 RoiDateUtilsSpec
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Spock → JUnit 5 Migration: RoiDateUtilsSpec</title> | |
| <style> | |
| * { box-sizing: border-box; margin: 0; padding: 0; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; padding: 20px; line-height: 1.6; } | |
| h1 { text-align: center; margin-bottom: 20px; color: #333; } | |
| .section { background: white; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); overflow: hidden; } | |
| .section-header { background: #2d3748; color: white; padding: 12px 16px; cursor: pointer; display: flex; justify-content: space-between; align-items: center; } | |
| .section-header:hover { background: #4a5568; } | |
| .section-header h2 { font-size: 16px; font-weight: 600; } | |
| .section-header .toggle { font-size: 12px; } | |
| .section-content { display: block; } | |
| .section-content.collapsed { display: none; } | |
| .diff-container { display: grid; grid-template-columns: 1fr 1fr; } | |
| .diff-panel { padding: 16px; overflow-x: auto; } | |
| .diff-panel.left { background: #fff5f5; border-right: 1px solid #e2e8f0; } | |
| .diff-panel.right { background: #f0fff4; } | |
| .diff-panel h3 { font-size: 12px; text-transform: uppercase; color: #718096; margin-bottom: 12px; letter-spacing: 0.5px; } | |
| pre { font-family: 'SF Mono', Monaco, 'Courier New', monospace; font-size: 13px; white-space: pre-wrap; word-wrap: break-word; } | |
| .left pre { color: #c53030; } | |
| .right pre { color: #276749; } | |
| .summary { background: #c6f6d5; border-left: 4px solid #38a169; padding: 12px 16px; margin: 0; } | |
| .summary p { color: #276749; font-size: 14px; } | |
| .summary strong { color: #22543d; } | |
| @media (max-width: 768px) { .diff-container { grid-template-columns: 1fr; } .diff-panel.left { border-right: none; border-bottom: 1px solid #e2e8f0; } } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>🦀 Spock → JUnit 5 Migration: RoiDateUtilsSpec</h1> | |
| <p style="text-align: center; color: #666; margin-bottom: 20px;">Story: <a href="https://app.shortcut.com/agorapulse/story/185875">sc185875</a> | PR: <a href="https://github.com/agorapulse/platform/pull/72700">#72700</a></p> | |
| <!-- Section: Imports --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>📦 Imports</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>package agorapulse.roi.core.utils | |
| import agorapulse.roi.core.models.types.RoiPeriodDates | |
| import spock.lang.Specification | |
| import java.time.Clock | |
| import java.time.LocalDate</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>package agorapulse.roi.core.utils; | |
| import agorapulse.roi.core.models.types.RoiPeriodDates; | |
| import org.junit.jupiter.api.DisplayName; | |
| import org.junit.jupiter.api.Test; | |
| import java.time.Clock; | |
| import java.time.LocalDate; | |
| import static org.assertj.core.api.Assertions.assertThat;</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Spock Specification import with JUnit 5 @Test and @DisplayName annotations, added AssertJ for fluent assertions.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Class Declaration --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🏗️ Class Declaration</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>class RoiDateUtilsSpec extends Specification {</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>class RoiDateUtilsTest {</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Removed Specification inheritance. No mocks needed, so no @ExtendWith annotation required. Renamed to *Test convention.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 1 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Test: should check dates when range is valid</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should check dates when range is valid'() { | |
| given: | |
| LocalDate startDate = LocalDate.parse('2020-01-01') | |
| LocalDate endDate = LocalDate.parse('2020-12-31') | |
| int rangeDaysLimit = -1 | |
| when: | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit) | |
| then: | |
| result.startDate == LocalDate.of(2020, 1, 1) | |
| result.endDate == LocalDate.of(2020, 12, 31) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| @DisplayName("should check dates when range is valid") | |
| void shouldCheckDatesWhenRangeIsValid() { | |
| // given | |
| LocalDate startDate = LocalDate.parse("2020-01-01"); | |
| LocalDate endDate = LocalDate.parse("2020-12-31"); | |
| int rangeDaysLimit = -1; | |
| // when | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit); | |
| // then | |
| assertThat(result.getStartDate()).isEqualTo(LocalDate.of(2020, 1, 1)); | |
| assertThat(result.getEndDate()).isEqualTo(LocalDate.of(2020, 12, 31)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Spock given/when/then blocks → comments. Groovy property access → Java getters. Implicit truth assertions → AssertJ assertThat.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 2 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Test: should check dates when range is valid with timezone</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should check dates when range is valid with timezone'() { | |
| given: | |
| LocalDate startDate = LocalDate.parse('2020-01-01') | |
| LocalDate endDate = LocalDate.parse('2020-12-31') | |
| int rangeDaysLimit = -1 | |
| when: | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit, 'Australia/Sydney') | |
| then: | |
| result.startDate == LocalDate.of(2020, 1, 1) | |
| result.endDate == LocalDate.of(2020, 12, 31) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| @DisplayName("should check dates when range is valid with timezone") | |
| void shouldCheckDatesWhenRangeIsValidWithTimezone() { | |
| // given | |
| LocalDate startDate = LocalDate.parse("2020-01-01"); | |
| LocalDate endDate = LocalDate.parse("2020-12-31"); | |
| int rangeDaysLimit = -1; | |
| // when | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit, "Australia/Sydney"); | |
| // then | |
| assertThat(result.getStartDate()).isEqualTo(LocalDate.of(2020, 1, 1)); | |
| assertThat(result.getEndDate()).isEqualTo(LocalDate.of(2020, 12, 31)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Same pattern - tests timezone parameter overload with valid date range.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 3 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Test: should default dates when range is not valid</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should default dates when range is not valid'() { | |
| given: | |
| LocalDate startDate = LocalDate.parse('2020-01-01') | |
| LocalDate endDate = LocalDate.parse('2021-12-31') | |
| int rangeDaysLimit = -1 | |
| when: | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit) | |
| then: | |
| result.startDate == LocalDate.now(Clock.systemDefaultZone()).minusDays(30) | |
| result.endDate == LocalDate.now(Clock.systemDefaultZone()).minusDays(1) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| @DisplayName("should default dates when range is not valid") | |
| void shouldDefaultDatesWhenRangeIsNotValid() { | |
| // given | |
| LocalDate startDate = LocalDate.parse("2020-01-01"); | |
| LocalDate endDate = LocalDate.parse("2021-12-31"); | |
| int rangeDaysLimit = -1; | |
| // when | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit); | |
| // then | |
| assertThat(result.getStartDate()).isEqualTo(LocalDate.now(Clock.systemDefaultZone()).minusDays(30)); | |
| assertThat(result.getEndDate()).isEqualTo(LocalDate.now(Clock.systemDefaultZone()).minusDays(1)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Tests fallback behavior when date range exceeds 1 year (invalid). Defaults to last 30 days.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 4 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Test: should default dates when range is not valid with timezone</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should default dates when range is not valid with timezone'() { | |
| given: | |
| LocalDate startDate = LocalDate.parse('2020-01-01') | |
| LocalDate endDate = LocalDate.parse('2021-12-31') | |
| int rangeDaysLimit = -1 | |
| when: | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit, 'Australia/Sydney') | |
| then: | |
| result.startDate == LocalDate.now(Clock.systemDefaultZone()).minusDays(30) | |
| result.endDate == LocalDate.now(Clock.systemDefaultZone()).minusDays(1) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| @DisplayName("should default dates when range is not valid with timezone") | |
| void shouldDefaultDatesWhenRangeIsNotValidWithTimezone() { | |
| // given | |
| LocalDate startDate = LocalDate.parse("2020-01-01"); | |
| LocalDate endDate = LocalDate.parse("2021-12-31"); | |
| int rangeDaysLimit = -1; | |
| // when | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildDates(startDate, endDate, rangeDaysLimit, "Australia/Sydney"); | |
| // then | |
| assertThat(result.getStartDate()).isEqualTo(LocalDate.now(Clock.systemDefaultZone()).minusDays(30)); | |
| assertThat(result.getEndDate()).isEqualTo(LocalDate.now(Clock.systemDefaultZone()).minusDays(1)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Same fallback behavior test with timezone parameter.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 5 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Test: should default dates when previous range is not valid</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should default dates when previous range is not valid'() { | |
| given: | |
| RoiPeriodDates roiPeriodDates = new RoiPeriodDates(LocalDate.of(2020, 1, 1), LocalDate.of(2020, 1, 31)) | |
| LocalDate previousStartDate = LocalDate.parse('2020-01-01') | |
| LocalDate previousEndDate = LocalDate.parse('2020-01-31') | |
| int rangeDaysLimit = 31 | |
| when: | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildPreviousDates(previousStartDate, previousEndDate, roiPeriodDates, rangeDaysLimit) | |
| then: | |
| result.startDate == LocalDate.of(2019, 12, 1) | |
| result.endDate == LocalDate.of(2019, 12, 31) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| @DisplayName("should default dates when previous range is not valid") | |
| void shouldDefaultDatesWhenPreviousRangeIsNotValid() { | |
| // given | |
| RoiPeriodDates roiPeriodDates = new RoiPeriodDates(LocalDate.of(2020, 1, 1), LocalDate.of(2020, 1, 31)); | |
| LocalDate previousStartDate = LocalDate.parse("2020-01-01"); | |
| LocalDate previousEndDate = LocalDate.parse("2020-01-31"); | |
| int rangeDaysLimit = 31; | |
| // when | |
| RoiPeriodDates result = RoiDateUtils.checkAndBuildPreviousDates(previousStartDate, previousEndDate, roiPeriodDates, rangeDaysLimit); | |
| // then | |
| assertThat(result.getStartDate()).isEqualTo(LocalDate.of(2019, 12, 1)); | |
| assertThat(result.getEndDate()).isEqualTo(LocalDate.of(2019, 12, 31)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Tests checkAndBuildPreviousDates method. RoiPeriodDates uses all-args constructor directly (same syntax in both languages).</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| function toggleSection(header) { | |
| const content = header.nextElementSibling; | |
| const toggle = header.querySelector('.toggle'); | |
| content.classList.toggle('collapsed'); | |
| toggle.textContent = content.classList.contains('collapsed') ? '▶' : '▼'; | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment