github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/schema_canonical_test.go (about) 1 package avro_test 2 3 import ( 4 "strconv" 5 "testing" 6 7 "github.com/hamba/avro/v2" 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 ) 11 12 // Test cases are taken from the reference implementation here: 13 // https://github.com/apache/avro/blob/master/share/test/data/schema-tests.txt 14 15 func TestSchema_Canonical(t *testing.T) { 16 tests := []struct { 17 input string 18 canonical string 19 }{ 20 { 21 input: `"null"`, 22 canonical: `"null"`, 23 }, 24 { 25 input: `{"type":"null"}`, 26 canonical: `"null"`, 27 }, 28 { 29 input: `"boolean"`, 30 canonical: `"boolean"`, 31 }, 32 { 33 input: `{"type":"boolean"}`, 34 canonical: `"boolean"`, 35 }, 36 { 37 input: `"int"`, 38 canonical: `"int"`, 39 }, 40 { 41 input: `{"type":"int"}`, 42 canonical: `"int"`, 43 }, 44 { 45 input: `{"type":"int","logicalType":"date"}`, 46 canonical: `{"type":"int","logicalType":"date"}`, 47 }, 48 { 49 input: `{"type":"int","logicalType":"time-millis"}`, 50 canonical: `{"type":"int","logicalType":"time-millis"}`, 51 }, 52 { 53 input: `{"type":"int"}`, 54 canonical: `"int"`, 55 }, 56 { 57 input: `"long"`, 58 canonical: `"long"`, 59 }, 60 { 61 input: `{"type":"long"}`, 62 canonical: `"long"`, 63 }, 64 { 65 input: `{"type":"long","logicalType":"time-micros"}`, 66 canonical: `{"type":"long","logicalType":"time-micros"}`, 67 }, 68 { 69 input: `{"type":"long","logicalType":"timestamp-millis"}`, 70 canonical: `{"type":"long","logicalType":"timestamp-millis"}`, 71 }, 72 { 73 input: `{"type":"long","logicalType":"timestamp-millis"}`, 74 canonical: `{"type":"long","logicalType":"timestamp-millis"}`, 75 }, 76 { 77 input: `"float"`, 78 canonical: `"float"`, 79 }, 80 { 81 input: `{"type":"float"}`, 82 canonical: `"float"`, 83 }, 84 { 85 input: `"double"`, 86 canonical: `"double"`, 87 }, 88 { 89 input: `{"type":"double"}`, 90 canonical: `"double"`, 91 }, 92 { 93 input: `"bytes"`, 94 canonical: `"bytes"`, 95 }, 96 { 97 input: `{"type":"bytes"}`, 98 canonical: `"bytes"`, 99 }, 100 { 101 input: `{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}`, 102 canonical: `{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}`, 103 }, 104 { 105 input: `{"type":"bytes","logicalType":"decimal","precision":4,"scale":0}`, 106 canonical: `{"type":"bytes","logicalType":"decimal","precision":4}`, 107 }, 108 { 109 input: `"string"`, 110 canonical: `"string"`, 111 }, 112 { 113 input: `{"type":"string"}`, 114 canonical: `"string"`, 115 }, 116 { 117 input: `{"type":"string","logicalType":"uuid"}`, 118 canonical: `{"type":"string","logicalType":"uuid"}`, 119 }, 120 { 121 input: `[ ]`, 122 canonical: `[]`, 123 }, 124 { 125 input: `[ "int" ]`, 126 canonical: `["int"]`, 127 }, 128 { 129 input: `[ "int" , {"type":"boolean"} ]`, 130 canonical: `["int","boolean"]`, 131 }, 132 { 133 input: `{"fields":[], "type":"error", "name":"foo"}`, 134 canonical: `{"name":"foo","type":"error","fields":[]}`, 135 }, 136 { 137 input: `{"fields":[], "type":"record", "name":"foo"}`, 138 canonical: `{"name":"foo","type":"record","fields":[]}`, 139 }, 140 { 141 input: `{"fields":[], "type":"record", "name":"foo", "namespace":"x.y"}`, 142 canonical: `{"name":"x.y.foo","type":"record","fields":[]}`, 143 }, 144 { 145 input: `{"fields":[], "type":"record", "name":"a.b.foo", "namespace":"x.y"}`, 146 canonical: `{"name":"a.b.foo","type":"record","fields":[]}`, 147 }, 148 { 149 input: `{"fields":[], "type":"record", "name":"foo", "doc":"Useful info"}`, 150 canonical: `{"name":"foo","type":"record","fields":[]}`, 151 }, 152 { 153 input: `{"fields":[], "type":"record", "name":"foo", "aliases":["foo","bar"]}`, 154 canonical: `{"name":"foo","type":"record","fields":[]}`, 155 }, 156 { 157 input: `{"fields":[], "type":"record", "name":"foo", "doc":"foo", "aliases":["foo","bar"]}`, 158 canonical: `{"name":"foo","type":"record","fields":[]}`, 159 }, 160 { 161 input: `{"fields":[{"type":{"type":"boolean"}, "name":"f1"}], "type":"record", "name":"foo"}`, 162 canonical: `{"name":"foo","type":"record","fields":[{"name":"f1","type":"boolean"}]}`, 163 }, 164 { 165 input: ` 166 { "fields":[{"type":"boolean", "aliases":[], "name":"f1", "default":true}, 167 {"order":"descending","name":"f2","doc":"Hello","type":"int"}], 168 "type":"record", "name":"foo" 169 }`, 170 canonical: `{"name":"foo","type":"record","fields":[{"name":"f1","type":"boolean"},{"name":"f2","type":"int"}]}`, 171 }, 172 { 173 input: `{"type":"enum", "name":"foo", "symbols":["A1"]}`, 174 canonical: `{"name":"foo","type":"enum","symbols":["A1"]}`, 175 }, 176 { 177 input: `{"namespace":"x.y.z", "type":"enum", "name":"foo", "doc":"foo bar", "symbols":["A1", "A2"]}`, 178 canonical: `{"name":"x.y.z.foo","type":"enum","symbols":["A1","A2"]}`, 179 }, 180 { 181 input: `{"name":"foo","type":"fixed","size":15}`, 182 canonical: `{"name":"foo","type":"fixed","size":15}`, 183 }, 184 { 185 input: `{"name":"foo","type":"fixed","logicalType":"duration","size":12}`, 186 canonical: `{"name":"foo","type":"fixed","size":12,"logicalType":"duration"}`, 187 }, 188 { 189 input: `{"name":"foo","type":"fixed","logicalType":"decimal","size":12,"precision":4,"scale":2}`, 190 canonical: `{"name":"foo","type":"fixed","size":12,"logicalType":"decimal","precision":4,"scale":2}`, 191 }, 192 { 193 input: `{"name":"foo","type":"fixed","logicalType":"decimal","size":12,"precision":4,"scale":2,"someProp":"foobar"}`, 194 canonical: `{"name":"foo","type":"fixed","size":12,"logicalType":"decimal","precision":4,"scale":2}`, 195 }, 196 { 197 input: `{"name":"foo","type":"fixed","logicalType":"decimal","size":12,"precision":4,"scale":0}`, 198 canonical: `{"name":"foo","type":"fixed","size":12,"logicalType":"decimal","precision":4}`, 199 }, 200 { 201 input: `{"namespace":"x.y.z", "type":"fixed", "name":"foo", "doc":"foo bar", "size":32}`, 202 canonical: `{"name":"x.y.z.foo","type":"fixed","size":32}`, 203 }, 204 { 205 input: `{ "items":{"type":"null"}, "type":"array"}`, 206 canonical: `{"type":"array","items":"null"}`, 207 }, 208 { 209 input: `{ "values":"string", "type":"map"}`, 210 canonical: `{"type":"map","values":"string"}`, 211 }, 212 { 213 input: ` 214 215 {"name":"PigValue","type":"record", 216 "fields":[{"name":"value", "type":["null", "int", "long", "PigValue"]}]} 217 `, 218 canonical: `{"name":"PigValue","type":"record","fields":[{"name":"value","type":["null","int","long","PigValue"]}]}`, 219 }, 220 { 221 input: `{ 222 "type":"record", 223 "namespace": "org.hamba.avro", 224 "name":"X", 225 "fields":[ 226 {"name":"value", "type":{ 227 "type":"record", 228 "name":"Y", 229 "fields":[ 230 {"name":"value", "type":"string"} 231 ] 232 }} 233 ] 234 }`, 235 canonical: `{"name":"org.hamba.avro.X","type":"record","fields":[{"name":"value","type":{"name":"org.hamba.avro.Y","type":"record","fields":[{"name":"value","type":"string"}]}}]}`, 236 }, 237 { 238 input: `{ 239 "type":"record", 240 "namespace": "org.hamba.avro", 241 "name":"X", 242 "fields":[ 243 {"name":"value", "type":{ 244 "type":"enum", 245 "name":"Y", 246 "symbols":["TEST"] 247 }} 248 ] 249 }`, 250 canonical: `{"name":"org.hamba.avro.X","type":"record","fields":[{"name":"value","type":{"name":"org.hamba.avro.Y","type":"enum","symbols":["TEST"]}}]}`, 251 }, 252 { 253 input: `{ 254 "type":"record", 255 "namespace": "org.hamba.avro", 256 "name":"X", 257 "fields":[ 258 {"name":"value", "type":{ 259 "type":"fixed", 260 "name":"Y", 261 "size":15 262 }} 263 ] 264 }`, 265 canonical: `{"name":"org.hamba.avro.X","type":"record","fields":[{"name":"value","type":{"name":"org.hamba.avro.Y","type":"fixed","size":15}}]}`, 266 }, 267 } 268 269 for i, test := range tests { 270 test := test 271 t.Run(strconv.Itoa(i), func(t *testing.T) { 272 t.Parallel() 273 274 s, err := avro.ParseWithCache(test.input, "", &avro.SchemaCache{}) 275 276 require.NoError(t, err) 277 assert.Equal(t, test.canonical, s.String()) 278 }) 279 } 280 }