Skip to content

adding isInArray and the isNotInArray and IsNotIn#10

Closed
kthehatter wants to merge 2 commits intomainfrom
feature/development
Closed

adding isInArray and the isNotInArray and IsNotIn#10
kthehatter wants to merge 2 commits intomainfrom
feature/development

Conversation

@kthehatter
Copy link
Owner

@kthehatter kthehatter commented Mar 16, 2025

Descriptions of the Functions

  1. IsNotIn

    Purpose: Validates that a given value is not present in a predefined list of disallowed values.
    How It Works: It takes a variadic list of disallowedValues (of type interface{}) and checks if the input value matches any of them using ==. If a match is found, it returns an error; otherwise, it returns nil.
    Error Message: "value must not be one of %v", where %v is the list of disallowed values.
    Use Case: Useful for ensuring a value isn’t one of a specific set (e.g., banning certain strings like "admin" or "root").
    Limitations: The comparison uses ==, which might not work as expected for complex types (e.g., slices or structs) unless they’re comparable.

  2. IsInArray

    Purpose: Validates that a given value is present in a provided array or slice.
    How It Works: It uses reflection (reflect.ValueOf) to iterate over the elements of the input array (of type interface{}) and checks if the value matches any element using Interface() == value. Returns nil if found, or an error if not.
    Error Message: "value is not in the array".
    Use Case: Ensures a value is within an allowed set (e.g., a dropdown menu’s options).
    Limitations: The error message doesn’t reflect the array’s contents, and reflection can be slow for large arrays.

  3. IsNotInArray

    Purpose: Validates that a given value is not present in a provided array or slice.
    How It Works: Similar to IsInArray, it iterates over the array using reflection. If the value matches any element, it returns an error; otherwise, it returns nil.
    Error Message: "value is in the array".
    Use Case: Ensures a value isn’t in a forbidden list (e.g., excluding reserved keywords).
    Limitations: Same as IsInArray—error message lacks context, and reflection is used.

Summary by CodeRabbit

  • New Features

    • Enhanced input validation by introducing new functions to check if values are present or absent in specified lists and arrays, providing clearer error feedback.
  • Tests

    • Expanded automated test coverage with new tests for the validation functions, ensuring reliable behavior for membership checks and additional scenarios in text transformations.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

The changes add three new validation functions to enhance membership checking: IsNotIn, IsInArray, and IsNotInArray in the validator/is.go file. Their corresponding test functions are added in validator/is_test.go to verify proper error handling and type matching. Additionally, a new test case is incorporated in validator/transformers_test.go within the TestReplace function to assess the replacement of multiple occurrences of a target substring.

Changes

Files Change Summary
validator/is.go
validator/is_test.go
Added three new validation functions (IsNotIn, IsInArray, IsNotInArray) along with corresponding test functions (TestIsNotIn, TestIsInArray, TestIsNotInArray) to enhance membership checking logic.
validator/transformers_test.go Introduced an extra test case in TestReplace to check that multiple instances of a target substring are correctly replaced.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Application
    participant Validator as New Validator
    participant Data as Array/Values

    Caller->>Validator: Invoke validation (e.g., IsInArray, IsNotInArray)
    Validator->>Data: Iterate over values
    alt Match Found
        Validator-->>Caller: Return error (or nil if non-match for IsNotInArray)
    else No Match Found
        Validator-->>Caller: Return nil (or error for IsInArray)
    end
Loading

Poem

Hoppin' in code, I skip and play,
New checks are here to save the day.
Arrays and values, in order they run,
No rogue matches—error or fun!
With each line of code, my heart goes thump,
A happy rabbit'll forever jump!
🐰💻 Hop on and celebrate the bump!

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 golangci-lint (1.62.2)

level=warning msg="[runner] Can't run linter goanalysis_metalinter: buildir: failed to load package : could not load export data: no export data for "github.com/gin-gonic/gin""
level=error msg="Running error: can't run linter goanalysis_metalinter\nbuildir: failed to load package : could not load export data: no export data for "github.com/gin-gonic/gin""

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 537a268 and 45c96ae.

📒 Files selected for processing (2)
  • validator/is.go (1 hunks)
  • validator/is_test.go (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
validator/is.go (1)

96-132: Add input validation for array functions

Both IsInArray and IsNotInArray functions lack validation for nil input and proper panic prevention.

Consider adding nil checks before using reflection operations:

func IsInArray(array interface{}) ValidatorFunc {
    return func(value interface{}) error {
+       if array == nil {
+           return fmt.Errorf("array parameter cannot be nil")
+       }
        // rest of the function...
    }
}

func IsNotInArray(array interface{}) ValidatorFunc {
    return func(value interface{}) error {
+       if array == nil {
+           return fmt.Errorf("array parameter cannot be nil")
+       }
        // rest of the function...
    }
}
validator/is_test.go (1)

116-170: Consider testing with more complex data types

The current tests only validate behavior with primitive types like strings and integers. Consider adding tests with complex types like structs, maps, or slices to ensure the validators work correctly with all data types.

Add test cases for complex types:

// In TestIsInArray
{
    "complex type in array", 
    []interface{}{"apple", map[string]int{"a": 1}}, 
    map[string]int{"a": 1}, 
    nil, // Should find it
},

// In TestIsNotInArray
{
    "complex type not in array", 
    []interface{}{"apple", map[string]int{"b": 2}},
    map[string]int{"a": 1}, 
    nil, // Should not find it
},
🧰 Tools
🪛 GitHub Actions: Go Tests

[error] 130-130: TestIsNotIn/wrong_type failed: expected error 'value must not be one of [apple banana cherry]', got


[error] 149-149: TestIsInArray/invalid_value failed: expected error 'value must be one of [apple banana cherry]', got 'value is not in the array'


[error] 149-149: TestIsInArray/wrong_type failed: expected error 'value must be one of [apple banana cherry]', got


[error] 167-167: TestIsNotInArray/invalid_value failed: expected error 'value must not be one of [apple banana cherry]', got 'value is in the array'


[error] 167-167: TestIsNotInArray/wrong_type failed: expected error 'value must not be one of [apple banana cherry]', got

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e075051 and 537a268.

📒 Files selected for processing (3)
  • validator/is.go (1 hunks)
  • validator/is_test.go (1 hunks)
  • validator/transformers_test.go (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Go Tests
validator/is_test.go

[error] 130-130: TestIsNotIn/wrong_type failed: expected error 'value must not be one of [apple banana cherry]', got


[error] 149-149: TestIsInArray/invalid_value failed: expected error 'value must be one of [apple banana cherry]', got 'value is not in the array'


[error] 149-149: TestIsInArray/wrong_type failed: expected error 'value must be one of [apple banana cherry]', got


[error] 167-167: TestIsNotInArray/invalid_value failed: expected error 'value must not be one of [apple banana cherry]', got 'value is in the array'


[error] 167-167: TestIsNotInArray/wrong_type failed: expected error 'value must not be one of [apple banana cherry]', got

🔇 Additional comments (1)
validator/transformers_test.go (1)

174-174: LGTM: Good test case addition

This new test case validates the Replace transformer's ability to handle multiple occurrences of the target substring in a single input string, which improves test coverage.

Comment on lines +96 to +106
// IsNotIn checks if a value is not in a predefined list of disallowed values.
func IsNotIn(disallowedValues ...interface{}) ValidatorFunc {
return func(value interface{}) error {
for _, disallowed := range disallowedValues {
if value == disallowed {
return fmt.Errorf("value must not be one of %v", disallowedValues)
}
}
return nil
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Implementation needs type handling improvement

The current implementation doesn't properly handle the "wrong type" case according to the failing test. When comparing values of different types using ==, Go returns false rather than an error.

func IsNotIn(disallowedValues ...interface{}) ValidatorFunc {
    return func(value interface{}) error {
        for _, disallowed := range disallowedValues {
-           if value == disallowed {
+           // Use reflect to better handle different types
+           if reflect.DeepEqual(value, disallowed) {
                return fmt.Errorf("value must not be one of %v", disallowedValues)
            }
        }
        return nil
    }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// IsNotIn checks if a value is not in a predefined list of disallowed values.
func IsNotIn(disallowedValues ...interface{}) ValidatorFunc {
return func(value interface{}) error {
for _, disallowed := range disallowedValues {
if value == disallowed {
return fmt.Errorf("value must not be one of %v", disallowedValues)
}
}
return nil
}
}
// IsNotIn checks if a value is not in a predefined list of disallowed values.
func IsNotIn(disallowedValues ...interface{}) ValidatorFunc {
return func(value interface{}) error {
for _, disallowed := range disallowedValues {
// Use reflect to better handle different types
if reflect.DeepEqual(value, disallowed) {
return fmt.Errorf("value must not be one of %v", disallowedValues)
}
}
return nil
}
}

Comment on lines 116 to 133
func TestIsNotIn(t *testing.T) {
isNotIn := IsNotIn("apple", "banana", "cherry")
tests := []struct {
name string
input interface{}
error error
}{
{"valid value", "grape", nil},
{"invalid value", "apple", errors.New("value must not be one of [apple banana cherry]")},
{"wrong type", 123, errors.New("value must not be one of [apple banana cherry]")},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := isNotIn(test.input)
require.Equal(t, test.error, err)
})
}
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure tests align with implementation behavior

The test expects IsNotIn to handle type mismatches differently than it currently does. This needs to be addressed in both the test and the implementation.


🏁 Script executed:

#!/bin/bash
# Check how other equality checks handle type mismatches in the codebase
echo "Checking implementations of equality checks in the validator package..."
rg "if .+ == .+\s+" validator/

Length of output: 1032


Action: Reconcile type mismatch handling in IsNotIn

The test in validator/is_test.go (lines 116–133) expects that passing a value of the wrong type (e.g., an integer 123) to the IsNotIn function produces an error with the message "value must not be one of [apple banana cherry]". However, based on how equality checks are implemented in the rest of the validator package (as seen in validator/is.go where comparisons like if value == allowed are used without special type handling), the current IsNotIn function likely does not treat type mismatches explicitly.

To resolve this discrepancy, you should either:

  • Update the implementation: Modify IsNotIn (likely in validator/is.go) to detect mismatched types and return the expected error message, or
  • Adjust the test: Change the expectation in TestIsNotIn so that the wrong-type case either returns no error or uses a different error message that aligns with the current behavior.

Please ensure that the chosen approach is consistent with how similar validations are handled elsewhere in the codebase.

🧰 Tools
🪛 GitHub Actions: Go Tests

[error] 130-130: TestIsNotIn/wrong_type failed: expected error 'value must not be one of [apple banana cherry]', got

Comment on lines +135 to +152
func TestIsInArray(t *testing.T) {
isInArray := IsInArray([]string{"apple", "banana", "cherry"})
tests := []struct {
name string
input interface{}
error error
}{
{"valid value", "apple", nil},
{"invalid value", "grape", errors.New("value must be one of [apple banana cherry]")},
{"wrong type", 123, errors.New("value must be one of [apple banana cherry]")},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := isInArray(test.input)
require.Equal(t, test.error, err)
})
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix error message assertion in tests

The test assertions don't match the current implementation's error messages, leading to test failures. Either update the tests to match the implementation or modify the implementation to match the tests.

func TestIsInArray(t *testing.T) {
    isInArray := IsInArray([]string{"apple", "banana", "cherry"})
    tests := []struct {
        name  string
        input interface{}
        error error
    }{
        {"valid value", "apple", nil},
-       {"invalid value", "grape", errors.New("value must be one of [apple banana cherry]")},
-       {"wrong type", 123, errors.New("value must be one of [apple banana cherry]")},
+       {"invalid value", "grape", errors.New("value is not in the array")},
+       {"wrong type", 123, nil}, // Current implementation returns nil for type mismatches
    }
    for _, test := range tests {
        t.Run(test.name, func(t *testing.T) {
            err := isInArray(test.input)
            require.Equal(t, test.error, err)
        })
    }
}

Note: The better approach is to fix the implementation as suggested in the is.go file review.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func TestIsInArray(t *testing.T) {
isInArray := IsInArray([]string{"apple", "banana", "cherry"})
tests := []struct {
name string
input interface{}
error error
}{
{"valid value", "apple", nil},
{"invalid value", "grape", errors.New("value must be one of [apple banana cherry]")},
{"wrong type", 123, errors.New("value must be one of [apple banana cherry]")},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := isInArray(test.input)
require.Equal(t, test.error, err)
})
}
}
func TestIsInArray(t *testing.T) {
isInArray := IsInArray([]string{"apple", "banana", "cherry"})
tests := []struct {
name string
input interface{}
error error
}{
{"valid value", "apple", nil},
{"invalid value", "grape", errors.New("value is not in the array")},
{"wrong type", 123, nil}, // Current implementation returns nil for type mismatches
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := isInArray(test.input)
require.Equal(t, test.error, err)
})
}
}
🧰 Tools
🪛 GitHub Actions: Go Tests

[error] 149-149: TestIsInArray/invalid_value failed: expected error 'value must be one of [apple banana cherry]', got 'value is not in the array'


[error] 149-149: TestIsInArray/wrong_type failed: expected error 'value must be one of [apple banana cherry]', got

Comment on lines 153 to 170
func TestIsNotInArray(t *testing.T) {
isNotInArray := IsNotInArray([]string{"apple", "banana", "cherry"})
tests := []struct {
name string
input interface{}
error error
}{
{"valid value", "grape", nil},
{"invalid value", "apple", errors.New("value must not be one of [apple banana cherry]")},
{"wrong type", 123, errors.New("value must not be one of [apple banana cherry]")},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := isNotInArray(test.input)
require.Equal(t, test.error, err)
})
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix error message assertion in tests

Similar to TestIsInArray, the error messages don't match the current implementation.

func TestIsNotInArray(t *testing.T) {
    isNotInArray := IsNotInArray([]string{"apple", "banana", "cherry"})
    tests := []struct {
        name  string
        input interface{}
        error error
    }{
        {"valid value", "grape", nil},
-       {"invalid value", "apple", errors.New("value must not be one of [apple banana cherry]")},
-       {"wrong type", 123, errors.New("value must not be one of [apple banana cherry]")},
+       {"invalid value", "apple", errors.New("value is in the array")},
+       {"wrong type", 123, nil}, // Current implementation returns nil for type mismatches
    }
    for _, test := range tests {
        t.Run(test.name, func(t *testing.T) {
            err := isNotInArray(test.input)
            require.Equal(t, test.error, err)
        })
    }
}

Note: The better approach is to fix the implementation as suggested in the is.go file review.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func TestIsNotInArray(t *testing.T) {
isNotInArray := IsNotInArray([]string{"apple", "banana", "cherry"})
tests := []struct {
name string
input interface{}
error error
}{
{"valid value", "grape", nil},
{"invalid value", "apple", errors.New("value must not be one of [apple banana cherry]")},
{"wrong type", 123, errors.New("value must not be one of [apple banana cherry]")},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := isNotInArray(test.input)
require.Equal(t, test.error, err)
})
}
}
func TestIsNotInArray(t *testing.T) {
isNotInArray := IsNotInArray([]string{"apple", "banana", "cherry"})
tests := []struct {
name string
input interface{}
error error
}{
{"valid value", "grape", nil},
{"invalid value", "apple", errors.New("value is in the array")},
{"wrong type", 123, nil}, // Current implementation returns nil for type mismatches
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := isNotInArray(test.input)
require.Equal(t, test.error, err)
})
}
}
🧰 Tools
🪛 GitHub Actions: Go Tests

[error] 167-167: TestIsNotInArray/invalid_value failed: expected error 'value must not be one of [apple banana cherry]', got 'value is in the array'


[error] 167-167: TestIsNotInArray/wrong_type failed: expected error 'value must not be one of [apple banana cherry]', got

@kthehatter kthehatter closed this Mar 16, 2025
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.

1 participant