Skip to content

fix: required rule fails for int/uint values equal to 0#311

Merged
inhere merged 1 commit intogookit:masterfrom
almas-x:fix-302
Sep 6, 2025
Merged

fix: required rule fails for int/uint values equal to 0#311
inhere merged 1 commit intogookit:masterfrom
almas-x:fix-302

Conversation

@almas-x
Copy link
Contributor

@almas-x almas-x commented Sep 5, 2025

close #302

This PR addresses an issue with the validation of required rules for numeric fields, specifically ensuring that zero values for int/uint types are handled correctly as valid input in certain required scenarios. The main changes involve updating the logic of required-related validation methods and adding a new helper to identify zero numeric values that should be considered valid.

Validation logic improvements for numeric zero values:

  • Added a new helper method isIgnoreableZeroNumeric to the Validation struct to detect if a field is a numeric type with a zero value, allowing such values to be considered valid for required rules.
  • Updated the Required, RequiredIf, RequiredUnless, RequiredWith, RequiredWithAll, RequiredWithout, and RequiredWithoutAll methods to use isIgnoreableZeroNumeric, ensuring that zero values for numeric types are not incorrectly treated as missing or empty. [1] [2] [3] [4] [5] [6] [7] [8] [9]

Testing enhancements:

  • Added a new test case TestIssue_302 to verify that required rules correctly accept zero values for int/uint fields, preventing regression on this behavior.
  • Minor adjustment in TestIssues_I36T2B to ensure a fresh map is used in validation, improving test reliability.

@almas-x almas-x marked this pull request as draft September 5, 2025 07:50
@almas-x almas-x marked this pull request as ready for review September 5, 2025 08:17
@coveralls
Copy link

Pull Request Test Coverage Report for Build 17487708601

Details

  • 23 of 23 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.01%) to 96.889%

Totals Coverage Status
Change from base Build 17451009562: 0.01%
Covered Lines: 2896
Relevant Lines: 2989

💛 - Coveralls

@inhere inhere requested a review from Copilot September 5, 2025 09:27
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a validation bug where the required rule incorrectly failed for numeric fields with zero values (0 for int/uint types). The fix ensures that zero is treated as a valid value for required validation rules, addressing issue #302.

Key changes:

  • Added isIgnoreableZeroNumeric helper method to identify zero-valued numeric fields that should be considered valid
  • Updated all required-related validation methods to use this helper, allowing zero values for numeric types to pass validation
  • Added comprehensive test coverage for the fix

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

File Description
validators.go Added isIgnoreableZeroNumeric helper and updated all required validation methods to handle numeric zero values correctly
issues_test.go Added regression test TestIssue_302 and fixed test isolation issue in existing test

Comment on lines +495 to +503
func (v *Validation) isIgnoreableZeroNumeric(field string) bool {
if v.data != nil && v.data.Type() == sourceMap {
if val, ok := v.data.Get(field); ok {
k := reflect.ValueOf(val).Kind()
return k >= reflect.Int && k <= reflect.Float64
}
}
return false
}
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic incorrectly returns true for all numeric types regardless of their actual value. It should check if the value is specifically zero. Currently, any numeric value (e.g., 42, -5, 3.14) would be considered 'ignoreable zero numeric', which is incorrect.

Copilot uses AI. Check for mistakes.
Comment on lines +217 to +220
return val != nil && !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
}
} else if Enum(dstVal, args) {
return val != nil && !IsEmpty(val)
return val != nil && !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Operator precedence issue: the || has lower precedence than &&, so this expression is evaluated as (val != nil && !IsEmpty(val)) || v.isIgnoreableZeroNumeric(sourceField). This means the helper method result is returned regardless of the val conditions, which may not be the intended logic. Consider adding parentheses for clarity: return (val != nil && !IsEmpty(val)) || v.isIgnoreableZeroNumeric(sourceField)

Copilot uses AI. Check for mistakes.
}
} else if Enum(dstVal, args) {
return val != nil && !IsEmpty(val)
return val != nil && !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same logical pattern !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField) is repeated across multiple validation methods. Consider extracting this into a helper method like isValidRequiredValue(sourceField, val) to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
if dstVal, has, _ := v.tryGet(dstField); has {
if !Enum(dstVal, values) {
return !IsEmpty(val)
return !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same logical pattern !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField) is repeated across multiple validation methods. Consider extracting this into a helper method like isValidRequiredValue(sourceField, val) to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
for _, field := range fields {
if _, has, zero := v.tryGet(field); has && !zero {
return !IsEmpty(val)
return !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same logical pattern !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField) is repeated across multiple validation methods. Consider extracting this into a helper method like isValidRequiredValue(sourceField, val) to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.

// all fields exist
return !IsEmpty(val)
return !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same logical pattern !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField) is repeated across multiple validation methods. Consider extracting this into a helper method like isValidRequiredValue(sourceField, val) to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
for _, field := range fields {
if _, has, zero := v.tryGet(field); !has || zero {
return !IsEmpty(val)
return !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same logical pattern !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField) is repeated across multiple validation methods. Consider extracting this into a helper method like isValidRequiredValue(sourceField, val) to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.

// all fields not exists, required
return !IsEmpty(val)
return !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same logical pattern !IsEmpty(val) || v.isIgnoreableZeroNumeric(sourceField) is repeated across multiple validation methods. Consider extracting this into a helper method like isValidRequiredValue(sourceField, val) to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
@inhere inhere merged commit 89af7f9 into gookit:master Sep 6, 2025
17 of 18 checks passed
@almas-x almas-x deleted the fix-302 branch September 6, 2025 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

对于数字类型 int uint 为什么数值是 0 时直接报 required 的信息

4 participants