File: field_precedence_test.go

package info (click to toggle)
golang-github-oschwald-maxminddb-golang-v2 2.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,132 kB
  • sloc: perl: 557; makefile: 3
file content (134 lines) | stat: -rw-r--r-- 3,577 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package decoder

import (
	"encoding/hex"
	"reflect"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// TestFieldPrecedenceRules tests json/v2 style field precedence behavior.
func TestFieldPrecedenceRules(t *testing.T) {
	// Test data: {"en": "Foo"}
	testData := "e142656e43466f6f"
	testBytes, err := hex.DecodeString(testData)
	require.NoError(t, err)

	t.Run("DirectFieldWinsOverEmbedded", func(t *testing.T) {
		type Embedded struct {
			En string `maxminddb:"en"`
		}
		target := &struct {
			Embedded

			En string `maxminddb:"en"` // Direct field should win
		}{}

		decoder := New(testBytes)
		err := decoder.Decode(0, target)
		require.NoError(t, err)

		assert.Equal(t, "Foo", target.En, "Direct field should be set")
		assert.Empty(t, target.Embedded.En, "Embedded field should not be set due to precedence")
	})

	t.Run("TaggedFieldWinsOverUntagged", func(t *testing.T) {
		type Untagged struct {
			En string // Untagged field
		}
		target := &struct {
			Untagged

			En string `maxminddb:"en"` // Tagged field should win
		}{}

		decoder := New(testBytes)
		err := decoder.Decode(0, target)
		require.NoError(t, err)

		assert.Equal(t, "Foo", target.En, "Tagged field should be set")
		assert.Empty(t, target.Untagged.En, "Untagged field should not be set")
	})

	t.Run("ShallowFieldWinsOverDeep", func(t *testing.T) {
		type DeepNested struct {
			En string `maxminddb:"en"` // Deeper field
		}
		type MiddleNested struct {
			DeepNested
		}
		target := &struct {
			MiddleNested

			En string `maxminddb:"en"` // Shallow field should win
		}{}

		decoder := New(testBytes)
		err := decoder.Decode(0, target)
		require.NoError(t, err)

		assert.Equal(t, "Foo", target.En, "Shallow field should be set")
		assert.Empty(t, target.DeepNested.En, "Deep field should not be set due to precedence")
	})
}

// TestEmbeddedPointerSupport tests support for embedded pointer types.
func TestEmbeddedPointerSupport(t *testing.T) {
	// Test data: {"data": "test"}
	testData := "e144646174614474657374"
	testBytes, err := hex.DecodeString(testData)
	require.NoError(t, err)

	type EmbeddedPointer struct {
		Data string `maxminddb:"data"`
	}

	target := &struct {
		*EmbeddedPointer

		Other string `maxminddb:"other"`
	}{}

	decoder := New(testBytes)
	err = decoder.Decode(0, target)
	require.NoError(t, err)

	// Test embedded pointer field access - this was causing nil pointer dereference before fix
	require.NotNil(t, target.EmbeddedPointer, "Embedded pointer should be initialized")
	assert.Equal(t, "test", target.Data)
}

// TestFieldCaching tests the field caching mechanism works with new precedence rules.
func TestFieldCaching(t *testing.T) {
	type Embedded struct {
		Field1 string `maxminddb:"field1"`
	}

	type TestStruct struct {
		Embedded

		Field2 int  `maxminddb:"field2"`
		Field3 bool `maxminddb:"field3"`
	}

	// Test that multiple instances use cached fields
	s1 := TestStruct{}
	s2 := TestStruct{}

	fields1 := cachedFields(reflect.ValueOf(s1))
	fields2 := cachedFields(reflect.ValueOf(s2))

	// Should be the same cached instance
	assert.Same(t, fields1, fields2, "Same struct type should use cached fields")

	// Verify field mapping includes embedded fields
	expectedFieldNames := []string{"field1", "field2", "field3"}

	assert.Len(t, fields1.namedFields, 3, "Should have 3 named fields")
	for _, name := range expectedFieldNames {
		assert.Contains(t, fields1.namedFields, name, "Should contain field: "+name)
		assert.NotNil(t, fields1.namedFields[name], "Field info should not be nil: "+name)
	}
}