diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml new file mode 100644 index 00000000000..bde18f4108f --- /dev/null +++ b/.github/workflows/sonarcloud.yml @@ -0,0 +1,47 @@ +name: SonarCloud Analysis + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +jobs: + sonarcloud: + name: SonarCloud Code Analysis + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: pcov, mbstring, xml, ctype, json, bcmath + coverage: pcov + + - name: Set up environment variables + run: | + echo "APP_ENV=testing" >> $GITHUB_ENV + echo "APP_KEY=base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" >> $GITHUB_ENV + echo "DB_CONNECTION=sqlite" >> $GITHUB_ENV + echo "DB_DATABASE=:memory:" >> $GITHUB_ENV + echo "APP_LOG_LEVEL=notice" >> $GITHUB_ENV + echo "AUDIT_LOG_LEVEL=emergency" >> $GITHUB_ENV + + - name: Install Composer dependencies + run: composer install --prefer-dist --no-progress --no-suggest --no-interaction + + - name: Run unit tests with coverage + run: ./vendor/bin/phpunit --testsuite=unit --coverage-clover=coverage.xml + + - name: SonarCloud Scan + uses: SonarSource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/phpunit.xml b/phpunit.xml index b4ce7ee3654..3d7f86cf490 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -61,7 +61,7 @@ + pathCoverage="false"> diff --git a/tests/unit/Support/AmountGetAmountJsConfigTest.php b/tests/unit/Support/AmountGetAmountJsConfigTest.php new file mode 100644 index 00000000000..1c5a625342a --- /dev/null +++ b/tests/unit/Support/AmountGetAmountJsConfigTest.php @@ -0,0 +1,203 @@ +assertSame($expected, $result); + } + + public static function provideFormatConfigurations(): iterable + { + yield 'parentheses around all, currency before, with space' => [ + true, + 0, + '-', + true, + '(%s %v)', + ]; + + yield 'parentheses around all, currency before, no space' => [ + false, + 0, + '-', + true, + '(%s%v)', + ]; + + yield 'parentheses around all, currency after, with space' => [ + true, + 0, + '-', + false, + '(%v %s)', + ]; + + yield 'parentheses around all, currency after, no space' => [ + false, + 0, + '-', + false, + '(%v%s)', + ]; + + yield 'sign before all, currency before, with space' => [ + true, + 1, + '-', + true, + '-%s %v', + ]; + + yield 'sign before all, currency before, no space' => [ + false, + 1, + '-', + true, + '-%s%v', + ]; + + yield 'sign before all, currency after, with space' => [ + true, + 1, + '-', + false, + '-%v %s', + ]; + + yield 'sign before all, currency after, no space' => [ + false, + 1, + '-', + false, + '-%v%s', + ]; + + yield 'sign after all, currency before, with space' => [ + true, + 2, + '-', + true, + '%s %v-', + ]; + + yield 'sign after all, currency before, no space' => [ + false, + 2, + '-', + true, + '%s%v-', + ]; + + yield 'sign after all, currency after, with space' => [ + true, + 2, + '-', + false, + '%v %s-', + ]; + + yield 'sign after all, currency after, no space' => [ + false, + 2, + '-', + false, + '%v%s-', + ]; + + yield 'sign before symbol, currency before, with space' => [ + true, + 3, + '-', + true, + '-%s %v', + ]; + + yield 'sign before symbol, currency before, no space' => [ + false, + 3, + '-', + true, + '-%s%v', + ]; + + yield 'sign before symbol, currency after, with space' => [ + true, + 3, + '-', + false, + '%v -%s', + ]; + + yield 'sign before symbol, currency after, no space' => [ + false, + 3, + '-', + false, + '%v-%s', + ]; + + yield 'sign after symbol, currency before, with space' => [ + true, + 4, + '-', + true, + '%s- %v', + ]; + + yield 'sign after symbol, currency before, no space' => [ + false, + 4, + '-', + true, + '%s-%v', + ]; + + yield 'sign after symbol, currency after, with space' => [ + true, + 4, + '-', + false, + '%v %s-', + ]; + + yield 'sign after symbol, currency after, no space' => [ + false, + 4, + '-', + false, + '%v%s-', + ]; + + yield 'positive sign, sign before all' => [ + true, + 1, + '+', + true, + '+%s %v', + ]; + + yield 'custom sign character' => [ + false, + 1, + '−', + false, + '−%v%s', + ]; + } +} diff --git a/tests/unit/Support/ParseDateStringRangeTest.php b/tests/unit/Support/ParseDateStringRangeTest.php new file mode 100644 index 00000000000..a34367ee194 --- /dev/null +++ b/tests/unit/Support/ParseDateStringRangeTest.php @@ -0,0 +1,149 @@ +parser = new ParseDateString(); + } + + #[DataProvider('provideDateRangeValidCases')] + public function testIsDateRangeReturnsTrueForValidRanges(string $date): void + { + $this->assertTrue($this->parser->isDateRange($date)); + } + + public static function provideDateRangeValidCases(): iterable + { + yield 'day range' => ['xxxx-xx-15']; + + yield 'month range' => ['xxxx-12-xx']; + + yield 'year range' => ['2020-xx-xx']; + + yield 'month and day range' => ['xxxx-03-25']; + + yield 'day and year range' => ['2023-xx-31']; + + yield 'month and year range' => ['2022-05-xx']; + } + + #[DataProvider('provideDateRangeInvalidCases')] + public function testIsDateRangeReturnsFalseForInvalidCases(string $date): void + { + $this->assertFalse($this->parser->isDateRange($date)); + } + + public static function provideDateRangeInvalidCases(): iterable + { + yield 'complete date' => ['2024-12-25']; + + yield 'all x' => ['xxxx-xx-xx']; + + yield 'wrong length' => ['xxxx-xx-xxx']; + + yield 'too short' => ['xxxx-xx-']; + + yield 'not 10 chars' => ['2024-12-2']; + + yield 'no x at all' => ['2024-12-25']; + } + + public function testParseRangeDayOnly(): void + { + $result = $this->parser->parseRange('xxxx-xx-09'); + $this->assertSame(['day' => '09'], $result); + } + + public function testParseRangeMonthOnly(): void + { + $result = $this->parser->parseRange('xxxx-11-xx'); + $this->assertSame(['month' => '11'], $result); + } + + public function testParseRangeYearOnly(): void + { + $result = $this->parser->parseRange('2020-xx-xx'); + $this->assertSame(['year' => '2020'], $result); + } + + public function testParseRangeMonthAndDay(): void + { + $result = $this->parser->parseRange('xxxx-02-28'); + $this->assertSame(['month' => '02', 'day' => '28'], $result); + } + + public function testParseRangeDayAndYear(): void + { + $result = $this->parser->parseRange('2023-xx-31'); + $this->assertSame(['year' => '2023', 'day' => '31'], $result); + } + + public function testParseRangeMonthAndYear(): void + { + $result = $this->parser->parseRange('2022-05-xx'); + $this->assertSame(['year' => '2022', 'month' => '05'], $result); + } + + #[DataProvider('provideDayRangeCases')] + public function testParseDayRange(string $input, string $expectedDay): void + { + $result = $this->parser->parseRange($input); + $this->assertArrayHasKey('day', $result); + $this->assertSame($expectedDay, $result['day']); + } + + public static function provideDayRangeCases(): iterable + { + yield 'first of month' => ['xxxx-xx-01', '01']; + + yield 'mid month' => ['xxxx-xx-15', '15']; + + yield 'end of month' => ['xxxx-xx-31', '31']; + } + + #[DataProvider('provideMonthRangeCases')] + public function testParseMonthRange(string $input, string $expectedMonth): void + { + $result = $this->parser->parseRange($input); + $this->assertArrayHasKey('month', $result); + $this->assertSame($expectedMonth, $result['month']); + } + + public static function provideMonthRangeCases(): iterable + { + yield 'January' => ['xxxx-01-xx', '01']; + + yield 'June' => ['xxxx-06-xx', '06']; + + yield 'December' => ['xxxx-12-xx', '12']; + } + + #[DataProvider('provideYearRangeCases')] + public function testParseYearRange(string $input, string $expectedYear): void + { + $result = $this->parser->parseRange($input); + $this->assertArrayHasKey('year', $result); + $this->assertSame($expectedYear, $result['year']); + } + + public static function provideYearRangeCases(): iterable + { + yield '20th century' => ['1999-xx-xx', '1999']; + + yield '21st century early' => ['2000-xx-xx', '2000']; + + yield '21st century recent' => ['2024-xx-xx', '2024']; + } +} diff --git a/tests/unit/Support/SteamBcroundTest.php b/tests/unit/Support/SteamBcroundTest.php new file mode 100644 index 00000000000..a50e611eaca --- /dev/null +++ b/tests/unit/Support/SteamBcroundTest.php @@ -0,0 +1,64 @@ +steam = new Steam(); + } + + #[DataProvider('provideNumbers')] + public function testBcroundReturnsExpectedValue(?string $input, int $precision, string $expected): void + { + $result = $this->steam->bcround($input, $precision); + $this->assertSame($expected, $result); + } + + public static function provideNumbers(): iterable + { + yield 'null input' => [null, 2, '0']; + + yield 'empty string' => ['', 2, '0']; + + yield 'whitespace only' => [' ', 2, '0']; + + yield 'integer no decimals' => ['123', 2, '123']; + + yield 'positive round up 2 places' => ['123.456', 2, '123.46']; + + yield 'positive round down 2 places' => ['123.444', 2, '123.44']; + + yield 'negative round up 2 places' => ['-123.456', 2, '-123.46']; + + yield 'negative round down 2 places' => ['-123.444', 2, '-123.44']; + + yield 'scientific notation simple' => ['1.23e2', 0, '123']; + + yield 'scientific notation with precision' => ['1.2345e1', 2, '12.35']; + + yield 'scientific notation negative' => ['-1.23e2', 1, '-123.0']; + + yield 'round to 0 places' => ['123.789', 0, '124']; + + yield 'round negative to 0 places' => ['-123.789', 0, '-124']; + + yield 'very small positive' => ['0.001', 2, '0.00']; + + yield 'very small negative' => ['-0.001', 2, '0.00']; + + yield 'zero with precision' => ['0', 2, '0']; + + yield 'zero string with precision' => ['0.00', 2, '0.00']; + } +}