1package core 2 3import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9) 10 11func TestWrite_returnsErrorIfTargetNotPtr(t *testing.T) { 12 // try to copy a value to a non-pointer 13 err := WriteAnswer(true, "hello", true) 14 // make sure there was an error 15 if err == nil { 16 t.Error("Did not encounter error when writing to non-pointer.") 17 } 18} 19 20func TestWrite_canWriteToBool(t *testing.T) { 21 // a pointer to hold the boolean value 22 ptr := true 23 24 // try to copy a false value to the pointer 25 WriteAnswer(&ptr, "", false) 26 27 // if the value is true 28 if ptr { 29 // the test failed 30 t.Error("Could not write a false bool to a pointer") 31 } 32} 33 34func TestWrite_canWriteString(t *testing.T) { 35 // a pointer to hold the boolean value 36 ptr := "" 37 38 // try to copy a false value to the pointer 39 err := WriteAnswer(&ptr, "", "hello") 40 if err != nil { 41 t.Error(err) 42 } 43 44 // if the value is not what we wrote 45 if ptr != "hello" { 46 t.Error("Could not write a string value to a pointer") 47 } 48} 49 50func TestWrite_canWriteSlice(t *testing.T) { 51 // a pointer to hold the value 52 ptr := []string{} 53 54 // copy in a value 55 WriteAnswer(&ptr, "", []string{"hello", "world"}) 56 57 // make sure there are two entries 58 assert.Equal(t, []string{"hello", "world"}, ptr) 59} 60 61func TestWrite_recoversInvalidReflection(t *testing.T) { 62 // a variable to mutate 63 ptr := false 64 65 // write a boolean value to the string 66 err := WriteAnswer(&ptr, "", "hello") 67 68 // if there was no error 69 if err == nil { 70 // the test failed 71 t.Error("Did not encounter error when forced invalid write.") 72 } 73} 74 75func TestWriteAnswer_handlesNonStructValues(t *testing.T) { 76 // the value to write to 77 ptr := "" 78 79 // write a value to the pointer 80 WriteAnswer(&ptr, "", "world") 81 82 // if we didn't change the value appropriate 83 if ptr != "world" { 84 // the test failed 85 t.Error("Did not write value to primitive pointer") 86 } 87} 88 89func TestWriteAnswer_canMutateStruct(t *testing.T) { 90 // the struct to hold the answer 91 ptr := struct{ Name string }{} 92 93 // write a value to an existing field 94 err := WriteAnswer(&ptr, "name", "world") 95 if err != nil { 96 // the test failed 97 t.Errorf("Encountered error while writing answer: %v", err.Error()) 98 // we're done here 99 return 100 } 101 102 // make sure we changed the field 103 if ptr.Name != "world" { 104 // the test failed 105 t.Error("Did not mutate struct field when writing answer.") 106 } 107} 108 109func TestWriteAnswer_canMutateMap(t *testing.T) { 110 // the map to hold the answer 111 ptr := make(map[string]interface{}) 112 113 // write a value to an existing field 114 err := WriteAnswer(&ptr, "name", "world") 115 if err != nil { 116 // the test failed 117 t.Errorf("Encountered error while writing answer: %v", err.Error()) 118 // we're done here 119 return 120 } 121 122 // make sure we changed the field 123 if ptr["name"] != "world" { 124 // the test failed 125 t.Error("Did not mutate map when writing answer.") 126 } 127} 128 129func TestWrite_returnsErrorIfInvalidMapType(t *testing.T) { 130 // try to copy a value to a non map[string]interface{} 131 ptr := make(map[int]string) 132 133 err := WriteAnswer(&ptr, "name", "world") 134 // make sure there was an error 135 if err == nil { 136 t.Error("Did not encounter error when writing to invalid map.") 137 } 138} 139 140func TestWrite_writesStringSliceToIntSlice(t *testing.T) { 141 // make a slice of int to write to 142 target := []int{} 143 144 // write the answer 145 err := WriteAnswer(&target, "name", []string{"1", "2", "3"}) 146 147 // make sure there was no error 148 assert.Nil(t, err, "WriteSlice to Int Slice") 149 // and we got what we wanted 150 assert.Equal(t, []int{1, 2, 3}, target) 151} 152 153func TestWrite_writesStringArrayToIntArray(t *testing.T) { 154 // make an array of int to write to 155 target := [3]int{} 156 157 // write the answer 158 err := WriteAnswer(&target, "name", [3]string{"1", "2", "3"}) 159 160 // make sure there was no error 161 assert.Nil(t, err, "WriteArray to Int Array") 162 // and we got what we wanted 163 assert.Equal(t, [3]int{1, 2, 3}, target) 164} 165 166func TestWriteAnswer_returnsErrWhenFieldNotFound(t *testing.T) { 167 // the struct to hold the answer 168 ptr := struct{ Name string }{} 169 170 // write a value to an existing field 171 err := WriteAnswer(&ptr, "", "world") 172 173 if err == nil { 174 // the test failed 175 t.Error("Did not encountered error while writing answer to non-existing field.") 176 } 177} 178 179func TestFindFieldIndex_canFindExportedField(t *testing.T) { 180 // create a reflective wrapper over the struct to look through 181 val := reflect.ValueOf(struct{ Name string }{}) 182 183 // find the field matching "name" 184 fieldIndex, err := findFieldIndex(val, "name") 185 // if something went wrong 186 if err != nil { 187 // the test failed 188 t.Error(err.Error()) 189 return 190 } 191 192 // make sure we got the right value 193 if val.Type().Field(fieldIndex).Name != "Name" { 194 // the test failed 195 t.Errorf("Did not find the correct field name. Expected 'Name' found %v.", val.Type().Field(fieldIndex).Name) 196 } 197} 198 199func TestFindFieldIndex_canFindTaggedField(t *testing.T) { 200 // the struct to look through 201 val := reflect.ValueOf(struct { 202 Username string `survey:"name"` 203 }{}) 204 205 // find the field matching "name" 206 fieldIndex, err := findFieldIndex(val, "name") 207 // if something went wrong 208 if err != nil { 209 // the test failed 210 t.Error(err.Error()) 211 return 212 } 213 214 // make sure we got the right value 215 if val.Type().Field(fieldIndex).Name != "Username" { 216 // the test failed 217 t.Errorf("Did not find the correct field name. Expected 'Username' found %v.", val.Type().Field(fieldIndex).Name) 218 } 219} 220 221func TestFindFieldIndex_canHandleCapitalAnswerNames(t *testing.T) { 222 // create a reflective wrapper over the struct to look through 223 val := reflect.ValueOf(struct{ Name string }{}) 224 225 // find the field matching "name" 226 fieldIndex, err := findFieldIndex(val, "Name") 227 // if something went wrong 228 if err != nil { 229 // the test failed 230 t.Error(err.Error()) 231 return 232 } 233 234 // make sure we got the right value 235 if val.Type().Field(fieldIndex).Name != "Name" { 236 // the test failed 237 t.Errorf("Did not find the correct field name. Expected 'Name' found %v.", val.Type().Field(fieldIndex).Name) 238 } 239} 240 241func TestFindFieldIndex_tagOverwriteFieldName(t *testing.T) { 242 // the struct to look through 243 val := reflect.ValueOf(struct { 244 Name string 245 Username string `survey:"name"` 246 }{}) 247 248 // find the field matching "name" 249 fieldIndex, err := findFieldIndex(val, "name") 250 // if something went wrong 251 if err != nil { 252 // the test failed 253 t.Error(err.Error()) 254 return 255 } 256 257 // make sure we got the right value 258 if val.Type().Field(fieldIndex).Name != "Username" { 259 // the test failed 260 t.Errorf("Did not find the correct field name. Expected 'Username' found %v.", val.Type().Field(fieldIndex).Name) 261 } 262} 263 264type testFieldSettable struct { 265 Values map[string]string 266} 267 268type testStringSettable struct { 269 Value string `survey:"string"` 270} 271 272type testTaggedStruct struct { 273 TaggedValue testStringSettable `survey:"tagged"` 274} 275 276type testPtrTaggedStruct struct { 277 TaggedValue *testStringSettable `survey:"tagged"` 278} 279 280func (t *testFieldSettable) WriteAnswer(name string, value interface{}) error { 281 if t.Values == nil { 282 t.Values = map[string]string{} 283 } 284 if v, ok := value.(string); ok { 285 t.Values[name] = v 286 return nil 287 } 288 return fmt.Errorf("Incompatible type %T", value) 289} 290 291func (t *testStringSettable) WriteAnswer(_ string, value interface{}) error { 292 t.Value = value.(string) 293 return nil 294} 295 296func TestWriteWithFieldSettable(t *testing.T) { 297 testSet1 := testFieldSettable{} 298 err := WriteAnswer(&testSet1, "values", "stringVal") 299 assert.Nil(t, err) 300 assert.Equal(t, map[string]string{"values": "stringVal"}, testSet1.Values) 301 302 testSet2 := testFieldSettable{} 303 err = WriteAnswer(&testSet2, "values", 123) 304 assert.Error(t, fmt.Errorf("Incompatible type int64"), err) 305 assert.Equal(t, map[string]string{}, testSet2.Values) 306 307 testString1 := testStringSettable{} 308 err = WriteAnswer(&testString1, "", "value1") 309 assert.Nil(t, err) 310 assert.Equal(t, testStringSettable{"value1"}, testString1) 311 312 testSetStruct := testTaggedStruct{} 313 err = WriteAnswer(&testSetStruct, "tagged", "stringVal1") 314 assert.Nil(t, err) 315 assert.Equal(t, testTaggedStruct{TaggedValue: testStringSettable{"stringVal1"}}, testSetStruct) 316 317 testPtrSetStruct := testPtrTaggedStruct{&testStringSettable{}} 318 err = WriteAnswer(&testPtrSetStruct, "tagged", "stringVal1") 319 assert.Nil(t, err) 320 assert.Equal(t, testPtrTaggedStruct{TaggedValue: &testStringSettable{"stringVal1"}}, testPtrSetStruct) 321} 322 323// CONVERSION TESTS 324func TestWrite_canStringToBool(t *testing.T) { 325 // a pointer to hold the boolean value 326 ptr := true 327 328 // try to copy a false value to the pointer 329 WriteAnswer(&ptr, "", "false") 330 331 // if the value is true 332 if ptr { 333 // the test failed 334 t.Error("Could not convert string to pointer type") 335 } 336} 337 338func TestWrite_canStringToInt(t *testing.T) { 339 // a pointer to hold the value 340 var ptr int = 1 341 342 // try to copy a value to the pointer 343 WriteAnswer(&ptr, "", "2") 344 345 // if the value is true 346 if ptr != 2 { 347 // the test failed 348 t.Error("Could not convert string to pointer type") 349 } 350} 351 352func TestWrite_canStringToInt8(t *testing.T) { 353 // a pointer to hold the value 354 var ptr int8 = 1 355 356 // try to copy a value to the pointer 357 WriteAnswer(&ptr, "", "2") 358 359 // if the value is true 360 if ptr != 2 { 361 // the test failed 362 t.Error("Could not convert string to pointer type") 363 } 364} 365 366func TestWrite_canStringToInt16(t *testing.T) { 367 // a pointer to hold the value 368 var ptr int16 = 1 369 370 // try to copy a value to the pointer 371 WriteAnswer(&ptr, "", "2") 372 373 // if the value is true 374 if ptr != 2 { 375 // the test failed 376 t.Error("Could not convert string to pointer type") 377 } 378} 379 380func TestWrite_canStringToInt32(t *testing.T) { 381 // a pointer to hold the value 382 var ptr int32 = 1 383 384 // try to copy a value to the pointer 385 WriteAnswer(&ptr, "", "2") 386 387 // if the value is true 388 if ptr != 2 { 389 // the test failed 390 t.Error("Could not convert string to pointer type") 391 } 392} 393 394func TestWrite_canStringToInt64(t *testing.T) { 395 // a pointer to hold the value 396 var ptr int64 = 1 397 398 // try to copy a value to the pointer 399 WriteAnswer(&ptr, "", "2") 400 401 // if the value is true 402 if ptr != 2 { 403 // the test failed 404 t.Error("Could not convert string to pointer type") 405 } 406} 407 408func TestWrite_canStringToUint(t *testing.T) { 409 // a pointer to hold the value 410 var ptr uint = 1 411 412 // try to copy a value to the pointer 413 WriteAnswer(&ptr, "", "2") 414 415 // if the value is true 416 if ptr != 2 { 417 // the test failed 418 t.Error("Could not convert string to pointer type") 419 } 420} 421 422func TestWrite_canStringToUint8(t *testing.T) { 423 // a pointer to hold the value 424 var ptr uint8 = 1 425 426 // try to copy a value to the pointer 427 WriteAnswer(&ptr, "", "2") 428 429 // if the value is true 430 if ptr != 2 { 431 // the test failed 432 t.Error("Could not convert string to pointer type") 433 } 434} 435 436func TestWrite_canStringToUint16(t *testing.T) { 437 // a pointer to hold the value 438 var ptr uint16 = 1 439 440 // try to copy a value to the pointer 441 WriteAnswer(&ptr, "", "2") 442 443 // if the value is true 444 if ptr != 2 { 445 // the test failed 446 t.Error("Could not convert string to pointer type") 447 } 448} 449 450func TestWrite_canStringToUint32(t *testing.T) { 451 // a pointer to hold the value 452 var ptr uint32 = 1 453 454 // try to copy a value to the pointer 455 WriteAnswer(&ptr, "", "2") 456 457 // if the value is true 458 if ptr != 2 { 459 // the test failed 460 t.Error("Could not convert string to pointer type") 461 } 462} 463 464func TestWrite_canStringToUint64(t *testing.T) { 465 // a pointer to hold the value 466 var ptr uint64 = 1 467 468 // try to copy a value to the pointer 469 WriteAnswer(&ptr, "", "2") 470 471 // if the value is true 472 if ptr != 2 { 473 // the test failed 474 t.Error("Could not convert string to pointer type") 475 } 476} 477 478func TestWrite_canStringToFloat32(t *testing.T) { 479 // a pointer to hold the value 480 var ptr float32 = 1.0 481 482 // try to copy a value to the pointer 483 WriteAnswer(&ptr, "", "2.5") 484 485 // if the value is true 486 if ptr != 2.5 { 487 // the test failed 488 t.Error("Could not convert string to pointer type") 489 } 490} 491 492func TestWrite_canStringToFloat64(t *testing.T) { 493 // a pointer to hold the value 494 var ptr float64 = 1.0 495 496 // try to copy a value to the pointer 497 WriteAnswer(&ptr, "", "2.5") 498 499 // if the value is true 500 if ptr != 2.5 { 501 // the test failed 502 t.Error("Could not convert string to pointer type") 503 } 504} 505 506func TestWrite_canConvertStructFieldTypes(t *testing.T) { 507 // the struct to hold the answer 508 ptr := struct { 509 Name string 510 Age uint 511 Male bool 512 Height float64 513 }{} 514 515 // write the values as strings 516 check(t, WriteAnswer(&ptr, "name", "Bob")) 517 check(t, WriteAnswer(&ptr, "age", "22")) 518 check(t, WriteAnswer(&ptr, "male", "true")) 519 check(t, WriteAnswer(&ptr, "height", "6.2")) 520 521 // make sure we changed the fields 522 if ptr.Name != "Bob" { 523 t.Error("Did not mutate Name when writing answer.") 524 } 525 526 if ptr.Age != 22 { 527 t.Error("Did not mutate Age when writing answer.") 528 } 529 530 if !ptr.Male { 531 t.Error("Did not mutate Male when writing answer.") 532 } 533 534 if ptr.Height != 6.2 { 535 t.Error("Did not mutate Height when writing answer.") 536 } 537} 538 539func check(t *testing.T, err error) { 540 if err != nil { 541 t.Fatalf("Encountered error while writing answer: %v", err.Error()) 542 } 543} 544