Skip to content

Conversation

zrbecker
Copy link
Contributor

@zrbecker zrbecker commented Sep 25, 2023

Summary

In EqualExportedValues, testify treats an Array as a Slice, however, the reflect library throws an error if the type passed to reflect.MakeSlice is not a Slice kind. This issue was identified in #1404

The result is a very simple test such as

func TestEqualExportedValuesWithArray(t *testing.T) {
	type S struct{ Values [2]int }
	require.EqualExportedValues(t, S{Values: [2]int{1, 2}}, S{Values: [2]int{1, 2}})
}

results in a panic

panic: reflect.MakeSlice of non-slice type

This PR adjusts the offending switch statement in copyExportedFields to handle arrays separately, and construct the array using reflect.New(reflect.ArrayOf(len, type)).Elem() instead of reflect.MakeSlice.

Changes

  • Changed copyExportedFields (used by EqualExportedValues) to handle Array type separately from Slices as they must be constructed differently.
  • Added a test case to TestEqualExportedValues to verify an array object can be set on object passed to EqualExportedValues.

Motivation

A user was unable to use EqualExportedValues if they had an exported array type nested somewhere in their struct.

A test like this will now pass

func TestEqualExportedValuesWithArray(t *testing.T) {
	type S struct{ Values [2]int }
	require.EqualExportedValues(t, S{Values: [2]int{1, 2}}, S{Values: [2]int{1, 2}})
}

Related issues

Closes #1404

@zrbecker
Copy link
Contributor Author

@HaraldNordgren Looks like this was introduce in #1379, I saw this along with the issue you are addressing in #1384.

@HaraldNordgren
Copy link
Contributor

Awesome!

@HaraldNordgren
Copy link
Contributor

HaraldNordgren commented Sep 25, 2023

I think this needs some more tests. And would it make sense to combine the array and slice paths more since the logic is so similar after instantiating? Something like this:

// copyExportedFields iterates downward through list data structures and creates a copy
// that only contains the exported struct fields.
func copyExportedFieldsList(expectedValue, result reflect.Value) reflect.Value {
	for i := 0; i < expectedValue.Len(); i++ {
		index := expectedValue.Index(i)
		if isNil(index) {
			continue
		}
		unexportedRemoved := copyExportedFields(index.Interface())
		result.Index(i).Set(reflect.ValueOf(unexportedRemoved))
	}
	return result
}

and then

	case reflect.Array:
		result := reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem()
		result = copyExportedFieldsList(expectedValue, result)
		return result.Interface()

	case reflect.Slice:
		result := reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len())
		result = copyExportedFieldsList(expectedValue, result)
		return result.Interface()

Copy link
Contributor

@HaraldNordgren HaraldNordgren left a comment

Choose a reason for hiding this comment

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

(See my comment above)

@HaraldNordgren
Copy link
Contributor

@dolmen @boyan-soubachov Can you take a look at this? It's a good change that should be merged to unbreak the code.

@dolmen dolmen added pkg-assert Change related to package testify/assert assert.EqualValues About equality bug hacktoberfest-accepted Hacktoberfest labels Oct 10, 2023
Copy link
Collaborator

@dolmen dolmen left a comment

Choose a reason for hiding this comment

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

The only difference between the reflect.Array and reflect.Slice blocks are how result is allocated.
Please refactor to keep a single switch block and just branch with an if for the construction of result.

@dolmen dolmen changed the title Fix bug where array is treated as slice in EqualExportedValues assert.EqualExportedValues: fix handling of arrays Oct 10, 2023
@zrbecker zrbecker requested a review from dolmen October 15, 2023 22:46
@zrbecker
Copy link
Contributor Author

@dolmen I moved the two cases into a single switch statement to reduce code duplication as requested.

Copy link
Collaborator

@dolmen dolmen left a comment

Choose a reason for hiding this comment

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

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert.EqualValues About equality bug hacktoberfest-accepted Hacktoberfest pkg-assert Change related to package testify/assert
Projects
None yet
Development

Successfully merging this pull request may close these issues.

EqualExportedValues panic when struct contains array
3 participants