feat: comprehensive Docker PHPT test infrastructure and BCMath improvements#38
feat: comprehensive Docker PHPT test infrastructure and BCMath improvements#38
Conversation
Ensure that inputs like '-0' or '-0.0' are correctly normalized to '0'. This fixes inconsistencies in handling special cases for zero values.
…rison The decimal parts of numbers are now padded to the specified scale length with zeros to ensure consistent comparison.
…nding` Consolidated duplicate logic for handling rounding operations in `floor` and `ceil` methods into a new private method `normalizeZeroForRounding`. This improves code maintainability and reduces redundancy.
…wers of zero Introduce support for recognizing `-0` and `-0.0` as valid exponents in `bcpow`. Added behavior to throw a `DivisionByZeroError` for negative powers of zero, aligning with PHP 8.4+ standards. Improved handling of negative base calculations by applying a negative sign only for odd integer exponents.
…puts into powmod
Remove the validateIntegerInputs method that was incorrectly stripping negative
signs from valid negative numbers, causing bcpowmod to fail with negative bases.
The method was only used in powmod and created unnecessary abstraction with a
complex constraint system. By inlining the logic directly:
- Fix sign removal bug that affected negative base calculations
- Preserve security measures (ltrim for whitespace handling)
- Add proper negative base handling for bcmath-compatible modulus operations
- Simplify code by removing 54 lines of unnecessary abstraction
- Improve maintainability with direct, readable validation logic
This resolves bcpowmod test failures where negative bases were incorrectly
processed as positive values (e.g., bcpowmod('-2', '5', '7') now correctly
returns '-4' instead of '4').
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
test(BCMathTest): update data provider and test method names for clarity
The scale_ini test is skipped because the bcmath.scale INI setting is ignored without the native extension.
docs: clarify bcmath.scale INI setting limitations in README
Updated the README to explain that the bcmath.scale INI setting is ignored when the native bcmath extension is not loaded. Added a workaround to use `bcscale()` instead.
fix: handle bcmath.scale INI setting fallback in polyfill
Updated `resolveScale` method to handle cases where `ini_get('bcmath.scale')` returns false due to the absence of the native bcmath extension. Default scale is set to 0 in such cases.
Add a dedicated error message for modulo by zero and implement a `checkModuloByZero` method to validate divisor inputs. Replace division by zero check with modulo by zero check in `bcmod`.
- Fix PHP_ROUND_HALF_DOWN implementation to properly handle "towards zero" rounding - For exactly 0.5: positive numbers round down, negative numbers round up (towards zero) - For > 0.5: always round away from zero regardless of sign - Add comprehensive test cases for HalfTowardsZero rounding mode - Update CI to enable bcround_half_down test (now passes) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Added PositiveInfinity to the RoundingMode enum polyfill for PHP 8.1-8.3. Updated BCMath to throw a ValueError for unsupported PositiveInfinity mode.
Pull Request ReviewThis is a comprehensive PR that introduces significant improvements to the BCMath polyfill. I've reviewed the code quality, security, performance, and test coverage. Here's my detailed feedback: ✅ Strengths
🔍 Code Quality & Best PracticesGood:
Areas for Improvement:
⚡ Performance ConsiderationsGood:
Potential Concerns:
🔒 SecurityNo security concerns identified. The changes maintain proper input validation and don't introduce any new attack vectors. 🧪 Test CoverageExcellent:
Suggestions:
🚨 Potential Issues
📋 Recommendations
🎯 Overall AssessmentThis is a high-quality PR that significantly improves the polyfill's compatibility with PHP's native bcmath. The Docker PHPT integration is particularly valuable. While there are some performance and maintainability considerations, the benefits far outweigh the concerns. Recommendation: Approve with minor suggestions addressed. Great work on this comprehensive improvement! 🚀 🤖 Generated with Claude Code |
73b216f to
5aa753c
Compare
🔍 Code Review - BCMath Polyfill PR #38Thank you for this comprehensive improvement to the BCMath polyfill! This is an excellent contribution with significant enhancements to functionality, testing infrastructure, and compatibility. Below is my detailed analysis: ✅ Strengths1. Docker PHPT Test Infrastructure
2. Critical Bug Fixes
3. Code Quality Improvements
🔍 Areas for Consideration1. Performance ConsiderationsIn src/BCMath.php:782-804 (bcpowmod negative base handling), computing the full power before modulus could cause performance issues for large exponents. Consider implementing a more efficient algorithm or documenting the limitation. 2. Sign Handling ComplexityThe sign handling logic in bcpow() is quite complex and could benefit from additional test cases covering edge cases like (-2.0)^3 vs (-2.1)^3. 3. Error Message ConsistencyThe codebase now has checkDivisionByZero() and checkModuloByZero() methods. Consider consolidating these or creating a more generic checkZeroDivisor(string $operation) method. 🛡️ Security & ReliabilityPositive Aspects:
Edge Case Coverage:The new test cases significantly improve reliability:
📋 RecommendationsHigh Priority:
Medium Priority:
Low Priority:
🎯 Overall AssessmentThis is an excellent contribution that significantly improves the polyfill's compatibility and reliability. The Docker PHPT integration alone is a major achievement. The bug fixes address real compatibility issues that would affect production usage. Recommendation: ✅ APPROVE - This PR substantially improves the codebase with well-tested fixes and infrastructure improvements. The areas I've highlighted are suggestions for future improvements rather than blockers for this PR. The core functionality is sound and the testing infrastructure is robust. Great work! 🚀 |
There was a problem hiding this comment.
Pull Request Overview
This PR introduces a comprehensive Docker-based PHPT test infrastructure for validating BCMath compatibility with PHP's official test suite and implements several critical bug fixes and enhancements to the BCMath polyfill.
- Add Docker-based test runner for PHP's official bcmath PHPT tests with CI/CD integration
- Fix critical BCMath bugs including HalfTowardsZero rounding for negative numbers and modulo by zero error messages
- Enhance BCMath functionality with better error handling, improved precision, and complete RoundingMode enum support
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/BCMathTest.php | Adds comprehensive test coverage for HalfTowardsZero rounding mode and improves bcpow zero base handling |
| src/BCMath.php | Implements critical bug fixes for modulo error messages, negative power handling, and HalfTowardsZero rounding |
| lib/RoundingMode.php | Adds PositiveInfinity case to RoundingMode enum for complete PHP 8.4 compatibility |
| README.md | Documents bcmath.scale INI setting limitations when native extension is not loaded |
| .github/workflows/ci.yml | Integrates Docker-based PHPT testing into CI pipeline with appropriate skip lists |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| // Convert to BigInteger for calculation | ||
| $baseBig = new BigInteger($baseParts[0].$baseParts[1]); | ||
|
|
||
| $sign = self::isNegative($baseBig) ? '-' : ''; | ||
| $baseIsNegative = self::isNegative($baseBig); |
There was a problem hiding this comment.
The variable $baseIsNegative should be determined before converting $baseBig to absolute value to ensure consistent state. Currently, the negative check happens after creating the BigInteger but before taking the absolute value, which works but is less clear.
| // Exactly 0.5 and negative: round towards zero (which means don't add anything - truncate) | ||
| // Do nothing - let truncation handle it | ||
| } | ||
| // For exactly 0.5 and positive: round towards zero (which is down, so don't add) |
There was a problem hiding this comment.
This empty conditional block with only comments should be removed or restructured. Either combine the conditions or make the intent clearer by restructuring the logic to avoid an empty block.
| // Exactly 0.5 and negative: round towards zero (which means don't add anything - truncate) | |
| // Do nothing - let truncation handle it | |
| } | |
| // For exactly 0.5 and positive: round towards zero (which is down, so don't add) | |
| // Exactly 0.5 and negative: round towards zero (which means don't add anything - let truncation handle it) | |
| } | |
| // For exactly 0.5 and positive: round towards zero (which is down, so don't add; let truncation handle it) |
| if (self::startsWithNegativeSign($baseInt)) { | ||
| $baseInt = ltrim($baseInt); | ||
| } |
There was a problem hiding this comment.
The ltrim($baseInt) call will remove all leading whitespace and zeros, not just the negative sign. This could incorrectly modify the base value. Use substr($baseInt, 1) instead to remove only the negative sign.
| $exponentParts = explode('.', $exponent, 2); | ||
| $exponentInt = $exponentParts[0] === '' ? '0' : $exponentParts[0]; | ||
| if (self::startsWithNegativeSign($exponentInt)) { | ||
| $exponentInt = ltrim($exponentInt); |
There was a problem hiding this comment.
Same issue as with $baseInt - ltrim() removes all leading whitespace and zeros, not just the negative sign. Use substr($exponentInt, 1) to remove only the negative sign.
| $exponentInt = ltrim($exponentInt); | |
| $exponentInt = substr($exponentInt, 1); |
| if (self::startsWithNegativeSign($modulusInt)) { | ||
| $modulusInt = ltrim($modulusInt); | ||
| } |
There was a problem hiding this comment.
Same issue as above - ltrim() removes all leading whitespace and zeros, not just the negative sign. Use substr($modulusInt, 1) to remove only the negative sign.
Summary
This PR introduces a comprehensive Docker-based PHPT test infrastructure and implements several critical bug fixes and enhancements to the BCMath polyfill.
🐳 Docker PHPT Test Infrastructure
🔧 BCMath Bug Fixes and Enhancements
Critical Fixes:
PHP_ROUND_HALF_DOWNimplementation for negative numbers with exactly 0.5bcmod()to match PHP's expected "Modulo by zero"bcpow()behavior for negative bases and zero powersEnhancements:
PositiveInfinityto enum polyfill for full PHP 8.4 compatibility📋 Test Coverage Improvements
🚀 CI/CD Improvements
Test Plan
🤖 Generated with Claude Code