github.com/jjjabc/fitsio@v0.0.0-20161215022839-d1807e9e818e/header_test.go (about) 1 // Copyright 2015 The astrogo Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fitsio 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "math/big" 11 "os" 12 "reflect" 13 "testing" 14 ) 15 16 func newBigInt(t *testing.T) big.Int { 17 var i big.Int 18 _, err := fmt.Sscanf("40002100000000422948", "%v", &i) 19 if err != nil { 20 t.Fatalf("error creating a big.Int: %v\n", err) 21 } 22 return i 23 } 24 25 func TestHeaderRW(t *testing.T) { 26 curdir, err := os.Getwd() 27 if err != nil { 28 t.Fatalf(err.Error()) 29 } 30 defer os.Chdir(curdir) 31 32 workdir, err := ioutil.TempDir("", "go-fitsio-test-") 33 if err != nil { 34 t.Fatalf(err.Error()) 35 } 36 defer os.RemoveAll(workdir) 37 38 err = os.Chdir(workdir) 39 if err != nil { 40 t.Fatalf(err.Error()) 41 } 42 43 table := struct { 44 name string 45 version int 46 cards []Card 47 bitpix int 48 axes []int 49 image interface{} 50 }{ 51 name: "new.fits", 52 version: 2, 53 cards: []Card{ 54 { 55 "EXTNAME", 56 "primary hdu", 57 "the primary HDU", 58 }, 59 { 60 "EXTVER", 61 2, 62 "the primary hdu version", 63 }, 64 { 65 "card_uint8", 66 byte(42), 67 "an uint8", 68 }, 69 { 70 "card_uint16", 71 uint16(42), 72 "an uint16", 73 }, 74 { 75 "card_uint32", 76 uint32(42), 77 "an uint32", 78 }, 79 { 80 "card_uint64", 81 uint64(42), 82 "an uint64", 83 }, 84 { 85 "card_int8", 86 int8(42), 87 "an int8", 88 }, 89 { 90 "card_int16", 91 int16(42), 92 "an int16", 93 }, 94 { 95 "card_int32", 96 int32(42), 97 "an int32", 98 }, 99 { 100 "card_int64", 101 int64(42), 102 "an int64", 103 }, 104 { 105 "card_int3264", 106 int(42), 107 "an int", 108 }, 109 { 110 "card_uintxx", 111 uint(42), 112 "an uint", 113 }, 114 { 115 "card_float32", 116 float32(666), 117 "a float32", 118 }, 119 { 120 "card_float64", 121 float64(666), 122 "a float64", 123 }, 124 { 125 "card_complex64", 126 complex(float32(42), float32(66)), 127 "a complex64", 128 }, 129 { 130 "card_complex128", 131 complex(float64(42), float64(66)), 132 "a complex128", 133 }, 134 { 135 "card_bigint", 136 newBigInt(t), 137 "a big int", 138 }, 139 }, 140 bitpix: 8, 141 axes: []int{}, 142 } 143 fname := "new.fits" 144 for _, fct := range []func(){ 145 // create 146 func() { 147 w, err := os.Create(fname) 148 if err != nil { 149 t.Fatalf("error creating new file [%v]: %v", fname, err) 150 } 151 defer w.Close() 152 153 f, err := Create(w) 154 if err != nil { 155 t.Fatalf("error creating new file [%v]: %v", fname, err) 156 } 157 defer f.Close() 158 159 phdr := NewHeader( 160 table.cards, 161 IMAGE_HDU, 162 table.bitpix, 163 table.axes, 164 ) 165 phdu, err := NewPrimaryHDU(phdr) 166 if err != nil { 167 t.Fatalf("error creating PHDU: %v", err) 168 } 169 defer phdu.Close() 170 171 hdr := phdu.Header() 172 if hdr.bitpix != table.bitpix { 173 t.Fatalf("expected BITPIX=%v. got %v", table.bitpix, hdr.bitpix) 174 } 175 176 name := phdu.Name() 177 if name != "primary hdu" { 178 t.Fatalf("expected EXTNAME==%q. got %q", "primary hdu", name) 179 } 180 181 vers := phdu.Version() 182 if vers != table.version { 183 t.Fatalf("expected EXTVER==%v. got %v", table.version, vers) 184 } 185 186 card := hdr.Get("EXTNAME") 187 if card == nil { 188 t.Fatalf("error retrieving card [EXTNAME]") 189 } 190 if card.Comment != "the primary HDU" { 191 t.Fatalf("expected EXTNAME.Comment==%q. got %q", "the primary HDU", card.Comment) 192 } 193 194 card = hdr.Get("EXTVER") 195 if card == nil { 196 t.Fatalf("error retrieving card [EXTVER]") 197 } 198 if card.Comment != "the primary hdu version" { 199 t.Fatalf("expected EXTVER.Comment==%q. got %q", "the primary hdu version", card.Comment) 200 201 } 202 203 for _, ref := range table.cards { 204 card := hdr.Get(ref.Name) 205 if card == nil { 206 t.Fatalf("error retrieving card [%v]", ref.Name) 207 } 208 rv := reflect.ValueOf(ref.Value) 209 var val interface{} 210 switch rv.Type().Kind() { 211 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 212 val = int(rv.Int()) 213 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 214 val = int(rv.Uint()) 215 case reflect.Float32, reflect.Float64: 216 val = rv.Float() 217 case reflect.Complex64, reflect.Complex128: 218 val = rv.Complex() 219 case reflect.String: 220 val = ref.Value.(string) 221 case reflect.Bool: 222 val = ref.Value.(bool) 223 case reflect.Struct: 224 switch ref.Value.(type) { 225 case big.Int: 226 val = ref.Value.(big.Int) 227 } 228 } 229 if !reflect.DeepEqual(card.Value, val) { 230 t.Fatalf( 231 "card %q. expected [%v](%T). got [%v](%T)", 232 ref.Name, 233 val, val, 234 card.Value, card.Value, 235 ) 236 } 237 if card.Comment != ref.Comment { 238 t.Fatalf("card %q. comment differ. expected %q. got %q", ref.Name, ref.Comment, card.Comment) 239 } 240 } 241 242 card = hdr.Get("NOT THERE") 243 if card != nil { 244 t.Fatalf("expected no card. got [%v]", card) 245 } 246 247 err = f.Write(phdu) 248 if err != nil { 249 t.Fatalf("error writing hdu to file: %v", err) 250 } 251 }, 252 // read-back 253 func() { 254 r, err := os.Open(fname) 255 if err != nil { 256 t.Fatalf("error opening file [%v]: %v", fname, err) 257 } 258 defer r.Close() 259 f, err := Open(r) 260 if err != nil { 261 buf, _ := ioutil.ReadFile(fname) 262 t.Fatalf("error opening file [%v]: %v\nbuf=%s\n", fname, err, string(buf)) 263 } 264 defer f.Close() 265 266 hdu := f.HDU(0) 267 hdr := hdu.Header() 268 if hdr.bitpix != table.bitpix { 269 t.Fatalf("expected BITPIX=%v. got %v", 8, hdr.bitpix) 270 } 271 272 name := hdu.Name() 273 if name != "primary hdu" { 274 t.Fatalf("expected EXTNAME==%q. got %q", "primary hdu", name) 275 } 276 277 vers := hdu.Version() 278 if vers != table.version { 279 t.Fatalf("expected EXTVER==%v. got %v", 2, vers) 280 } 281 282 card := hdr.Get("EXTNAME") 283 if card == nil { 284 t.Fatalf("error retrieving card [EXTNAME]") 285 } 286 if card.Comment != "the primary HDU" { 287 t.Fatalf("expected EXTNAME.Comment==%q. got %q", "the primary HDU", card.Comment) 288 } 289 290 card = hdr.Get("EXTVER") 291 if card == nil { 292 t.Fatalf("error retrieving card [EXTVER]") 293 } 294 if card.Comment != "the primary hdu version" { 295 t.Fatalf("expected EXTVER.Comment==%q. got %q", "the primary hdu version", card.Comment) 296 297 } 298 299 for _, ref := range table.cards { 300 card := hdr.Get(ref.Name) 301 if card == nil { 302 t.Fatalf("error retrieving card [%v]", ref.Name) 303 } 304 305 rv := reflect.ValueOf(ref.Value) 306 var val interface{} 307 switch rv.Type().Kind() { 308 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 309 val = int(rv.Int()) 310 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 311 val = int(rv.Uint()) 312 case reflect.Float32, reflect.Float64: 313 val = rv.Float() 314 case reflect.Complex64, reflect.Complex128: 315 val = rv.Complex() 316 case reflect.String: 317 val = ref.Value.(string) 318 case reflect.Bool: 319 val = ref.Value.(bool) 320 case reflect.Struct: 321 switch ref.Value.(type) { 322 case big.Int: 323 val = ref.Value.(big.Int) 324 } 325 } 326 if !reflect.DeepEqual(card.Value, val) { 327 t.Fatalf( 328 "card %q. expected [%v](%T). got [%v](%T)", 329 ref.Name, 330 val, val, 331 card.Value, card.Value, 332 ) 333 } 334 335 if card.Comment != ref.Comment { 336 t.Fatalf("card %q. comment differ. expected %q. got %q", ref.Name, ref.Comment, card.Comment) 337 } 338 } 339 340 card = hdr.Get("NOT THERE") 341 if card != nil { 342 t.Fatalf("expected no card. got [%v]", card) 343 } 344 }, 345 } { 346 fct() 347 } 348 } 349 350 func TestRWHeaderLine(t *testing.T) { 351 for _, table := range []struct { 352 line []byte 353 card *Card 354 err error 355 }{ 356 { 357 line: []byte("SIMPLE = T / file does conform to FITS standard "), 358 card: &Card{ 359 Name: "SIMPLE", 360 Value: true, 361 Comment: "file does conform to FITS standard", 362 }, 363 err: nil, 364 }, 365 { 366 line: []byte("BITPIX = 16 / number of bits per data pixel "), 367 card: &Card{ 368 Name: "BITPIX", 369 Value: 16, 370 Comment: "number of bits per data pixel", 371 }, 372 err: nil, 373 }, 374 { 375 line: []byte("EXTNAME = 'primary hdu' / the primary HDU "), 376 card: &Card{ 377 Name: "EXTNAME", 378 Value: "primary hdu", 379 Comment: "the primary HDU", 380 }, 381 err: nil, 382 }, 383 { 384 line: []byte("STRING = 'a / ' / comment "), 385 card: &Card{ 386 Name: "STRING", 387 Value: "a /", 388 Comment: "comment", 389 }, 390 err: nil, 391 }, 392 { 393 line: []byte("STRING = ' a / ' / comment "), 394 card: &Card{ 395 Name: "STRING", 396 Value: " a /", 397 Comment: "comment", 398 }, 399 err: nil, 400 }, 401 { 402 line: []byte("STRING = ' a / / comment |'"), 403 card: &Card{ 404 Name: "STRING", 405 Value: " a / / comment |", 406 Comment: "", 407 }, 408 err: nil, 409 }, 410 { 411 line: []byte("STRING = ' a / / comment '"), 412 card: &Card{ 413 Name: "STRING", 414 Value: " a / / comment", 415 Comment: "", 416 }, 417 err: nil, 418 }, 419 { 420 line: []byte("STRING = 'a / ''' / comment "), 421 card: &Card{ 422 Name: "STRING", 423 Value: "a / '", 424 Comment: "comment", 425 }, 426 err: nil, 427 }, 428 { 429 line: []byte("COMPLEX = (42.0, 66.0) / comment "), 430 card: &Card{ 431 Name: "COMPLEX", 432 Value: complex(42, 66), 433 Comment: "comment", 434 }, 435 err: nil, 436 }, 437 { 438 line: []byte("COMPLEX = (42.0,66.0) / comment "), 439 card: &Card{ 440 Name: "COMPLEX", 441 Value: complex(42, 66), 442 Comment: "comment", 443 }, 444 err: nil, 445 }, 446 { 447 line: []byte("COMPLEX = (42,66) / comment "), 448 card: &Card{ 449 Name: "COMPLEX", 450 Value: complex(42, 66), 451 Comment: "comment", 452 }, 453 err: nil, 454 }, 455 { 456 line: []byte("COMPLEX = (42.0,66) / comment "), 457 card: &Card{ 458 Name: "COMPLEX", 459 Value: complex(42, 66), 460 Comment: "comment", 461 }, 462 err: nil, 463 }, 464 { 465 line: []byte("COMPLEX = (42,66.0) / comment "), 466 card: &Card{ 467 Name: "COMPLEX", 468 Value: complex(42, 66), 469 Comment: "comment", 470 }, 471 err: nil, 472 }, 473 { 474 line: []byte("COMPLEX = (42.000,66.0000) / comment "), 475 card: &Card{ 476 Name: "COMPLEX", 477 Value: complex(42, 66), 478 Comment: "comment", 479 }, 480 err: nil, 481 }, 482 } { 483 card, err := parseHeaderLine(table.line) 484 if !reflect.DeepEqual(err, table.err) { 485 t.Fatalf("expected error [%v]. got: %v", table.err, err) 486 } 487 if !reflect.DeepEqual(card, table.card) { 488 t.Fatalf("cards differ.\nexp= %#v\ngot= %#v", table.card, card) 489 } 490 491 line, err := makeHeaderLine(card) 492 if err != nil { 493 t.Fatalf("error making header-line: %v (%s)", err, string(line)) 494 } 495 } 496 497 for _, table := range []struct { 498 line []byte 499 err error 500 }{ 501 { 502 line: []byte("SIMPLE= T / FITS file"), 503 err: fmt.Errorf("fitsio: invalid header line length"), 504 }, 505 { 506 line: []byte("STRING = 'foo / comment "), 507 err: fmt.Errorf(`fitsio: string ends prematurely ("'foo / comment ")`), 508 }, 509 { 510 line: []byte("STRING = 'foo '' / comment "), 511 err: fmt.Errorf(`fitsio: string ends prematurely ("'foo '' / comment ")`), 512 }, 513 } { 514 card, err := parseHeaderLine(table.line) 515 if !reflect.DeepEqual(err, table.err) { 516 t.Fatalf("expected error [%v]. got: %v\ncard=%#v", table.err, err, card) 517 } 518 if card != nil { 519 t.Fatalf("expected a nil card. got= %#v", card) 520 } 521 } 522 } 523 524 func TestMakeHeaderLine(t *testing.T) { 525 for _, table := range []struct { 526 card *Card 527 line []byte 528 err error 529 }{ 530 { 531 card: &Card{ 532 Name: "SIMPLE", 533 Value: true, 534 Comment: "file does conform to FITS standard", 535 }, 536 line: []byte("SIMPLE = T / file does conform to FITS standard "), 537 err: nil, 538 }, 539 { 540 line: []byte("STRING = ' a / / no-comment 1&'CONTINUE '2| ' COMMENT my-comment "), 541 card: &Card{ 542 Name: "STRING", 543 Value: " a / / no-comment 12|", 544 Comment: "my-comment", 545 }, 546 err: nil, 547 }, 548 { 549 line: []byte("STRING = ' a / / no-comment 1&'CONTINUE '2| ' "), 550 card: &Card{ 551 Name: "STRING", 552 Value: " a / / no-comment 12|", 553 Comment: "", 554 }, 555 err: nil, 556 }, 557 { 558 line: []byte("STRING = ' a / / no-comment |&'CONTINUE '0123456789012345678901234567890123456789012345678901234567890123456&'CONTINUE '7890123456789|' "), 559 card: &Card{ 560 Name: "STRING", 561 Value: " a / / no-comment |01234567890123456789012345678901234567890123456789012345678901234567890123456789|", 562 Comment: "", 563 }, 564 err: nil, 565 }, 566 { 567 line: []byte("STRING = ' a / / no-comment |&'CONTINUE '0123456789012345678901234567890123456789012345678901234567890123456&'CONTINUE '7890123456789|' COMMENT my-comment "), 568 card: &Card{ 569 Name: "STRING", 570 Value: " a / / no-comment |01234567890123456789012345678901234567890123456789012345678901234567890123456789|", 571 Comment: "my-comment", 572 }, 573 err: nil, 574 }, 575 { 576 line: []byte("COMMENT * "), 577 card: &Card{ 578 Name: "COMMENT", 579 Value: "", 580 Comment: "*", 581 }, 582 err: nil, 583 }, 584 } { 585 line, err := makeHeaderLine(table.card) 586 if !reflect.DeepEqual(err, table.err) { 587 t.Fatalf("expected error [%v]. got: %v\nline=%q", table.err, err, string(line)) 588 } 589 if !reflect.DeepEqual(line, table.line) { 590 t.Fatalf("bline differ.\nexp=%q\ngot=%q", string(table.line), string(line)) 591 } 592 } 593 } 594 595 // EOF