github.com/astrogo/cfitsio@v0.1.0/table_test.go (about)

     1  package cfitsio
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  )
    10  
    11  func TestTable(t *testing.T) {
    12  	for _, table := range g_tables {
    13  		fname := table.fname
    14  		f, err := Open(fname, ReadOnly)
    15  		if err != nil {
    16  			t.Fatalf("error opening file [%v]: %v", fname, err)
    17  		}
    18  
    19  		for i := range f.HDUs() {
    20  			hdu, ok := f.HDU(i).(*Table)
    21  			if !ok {
    22  				continue
    23  			}
    24  			for irow := int64(0); irow < hdu.NumRows(); irow++ {
    25  				err := hdu.readRow(irow)
    26  				if err != nil {
    27  					t.Fatalf(
    28  						"error reading row [%v] (fname=%v, table=%v): %v",
    29  						irow, fname, hdu.Name(), err,
    30  					)
    31  				}
    32  			}
    33  		}
    34  	}
    35  }
    36  
    37  func TestTableNext(t *testing.T) {
    38  	for _, table := range g_tables {
    39  		fname := table.fname
    40  		f, err := Open(fname, ReadOnly)
    41  		if err != nil {
    42  			t.Fatalf("error opening file [%v]: %v", fname, err)
    43  		}
    44  
    45  		for i := range f.HDUs() {
    46  			hdu, ok := f.HDU(i).(*Table)
    47  			if !ok {
    48  				continue
    49  			}
    50  
    51  			nrows := hdu.NumRows()
    52  			// iter over all rows
    53  			rows, err := hdu.Read(0, nrows)
    54  			if err != nil {
    55  				t.Fatalf("table.Read: %v", err)
    56  			}
    57  			count := int64(0)
    58  			for rows.Next() {
    59  				count++
    60  			}
    61  			err = rows.Err()
    62  			if err != nil {
    63  				t.Fatalf("rows.Err: %v", err)
    64  			}
    65  			if count != nrows {
    66  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows, count)
    67  			}
    68  
    69  			// iter over no row
    70  			rows, err = hdu.Read(0, 0)
    71  			if err != nil {
    72  				t.Fatalf("table.Read: %v", err)
    73  			}
    74  			count = int64(0)
    75  			for rows.Next() {
    76  				count++
    77  			}
    78  			err = rows.Err()
    79  			if err != nil {
    80  				t.Fatalf("rows.Err: %v", err)
    81  			}
    82  			if count != 0 {
    83  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", 0, count)
    84  			}
    85  
    86  			// iter over 1 row
    87  			rows, err = hdu.Read(0, 1)
    88  			if err != nil {
    89  				t.Fatalf("table.Read: %v", err)
    90  			}
    91  			count = int64(0)
    92  			for rows.Next() {
    93  				count++
    94  			}
    95  			err = rows.Err()
    96  			if err != nil {
    97  				t.Fatalf("rows.Err: %v", err)
    98  			}
    99  			if count != 1 {
   100  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", 1, count)
   101  			}
   102  
   103  			// iter over all rows
   104  			rows, err = hdu.Read(0, nrows)
   105  			if err != nil {
   106  				t.Fatalf("table.Read: %v", err)
   107  			}
   108  			count = int64(0)
   109  			for rows.Next() {
   110  				count++
   111  			}
   112  			err = rows.Err()
   113  			if err != nil {
   114  				t.Fatalf("rows.Err: %v", err)
   115  			}
   116  			if count != nrows {
   117  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows, count)
   118  			}
   119  
   120  			// iter over all rows +1
   121  			rows, err = hdu.Read(0, nrows+1)
   122  			if err != nil {
   123  				t.Fatalf("table.Read: %v", err)
   124  			}
   125  			count = int64(0)
   126  			for rows.Next() {
   127  				count++
   128  			}
   129  			err = rows.Err()
   130  			if err != nil {
   131  				t.Fatalf("rows.Err: %v", err)
   132  			}
   133  			if count != nrows {
   134  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows, count)
   135  			}
   136  
   137  			// iter over all rows -1
   138  			rows, err = hdu.Read(1, nrows)
   139  			if err != nil {
   140  				t.Fatalf("table.Read: %v", err)
   141  			}
   142  			count = int64(0)
   143  			for rows.Next() {
   144  				count++
   145  			}
   146  			err = rows.Err()
   147  			if err != nil {
   148  				t.Fatalf("rows.Err: %v", err)
   149  			}
   150  			if count != nrows-1 {
   151  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows-1, count)
   152  			}
   153  
   154  			// iter over [1,1+maxrows -1)
   155  			rows, err = hdu.Read(1, nrows-1)
   156  			if err != nil {
   157  				t.Fatalf("table.Read: %v", err)
   158  			}
   159  			count = int64(0)
   160  			for rows.Next() {
   161  				count++
   162  			}
   163  			err = rows.Err()
   164  			if err != nil {
   165  				t.Fatalf("rows.Err: %v", err)
   166  			}
   167  			exp := nrows - 2
   168  			if exp <= 0 {
   169  				exp = 0
   170  			}
   171  			if count != exp {
   172  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", exp, count)
   173  			}
   174  
   175  			// iter over last row
   176  			rows, err = hdu.Read(nrows-1, nrows)
   177  			if err != nil {
   178  				t.Fatalf("table.Read: %v", err)
   179  			}
   180  			count = int64(0)
   181  			for rows.Next() {
   182  				count++
   183  			}
   184  			err = rows.Err()
   185  			if err != nil {
   186  				t.Fatalf("rows.Err: %v", err)
   187  			}
   188  			if count != 1 {
   189  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", 1, count)
   190  			}
   191  
   192  		}
   193  	}
   194  }
   195  
   196  func TestTableErrScan(t *testing.T) {
   197  	for _, table := range g_tables {
   198  		fname := table.fname
   199  		f, err := Open(fname, ReadOnly)
   200  		if err != nil {
   201  			t.Fatalf("error opening file [%v]: %v", fname, err)
   202  		}
   203  
   204  		for i := range f.HDUs() {
   205  			hdu, ok := f.HDU(i).(*Table)
   206  			if !ok {
   207  				continue
   208  			}
   209  			nrows := hdu.NumRows()
   210  			rows, err := hdu.Read(0, nrows)
   211  			if err != nil {
   212  				t.Fatalf("table.Read: %v", err)
   213  			}
   214  			count := int64(0)
   215  			for rows.Next() {
   216  				count++
   217  				err = rows.Scan()
   218  				if err != nil {
   219  					t.Fatalf("rows.Scan: error: %v", err)
   220  				}
   221  
   222  				dummy := 0
   223  				err = rows.Scan(&dummy) // none of the tables has only 1 field
   224  				if err == nil {
   225  					t.Fatalf("rows.Scan: expected a failure")
   226  				}
   227  			}
   228  			err = rows.Err()
   229  			if err != nil {
   230  				t.Fatalf("rows.Err: %v", err)
   231  			}
   232  			if count != nrows {
   233  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows, count)
   234  			}
   235  		}
   236  	}
   237  }
   238  
   239  func TestTableScan(t *testing.T) {
   240  	for _, table := range g_tables {
   241  		fname := table.fname
   242  		f, err := Open(fname, ReadOnly)
   243  		if err != nil {
   244  			t.Fatalf("error opening file [%v]: %v", fname, err)
   245  		}
   246  
   247  		for i := range f.HDUs() {
   248  			hdu, ok := f.HDU(i).(*Table)
   249  			if !ok {
   250  				continue
   251  			}
   252  			nrows := hdu.NumRows()
   253  			rows, err := hdu.Read(0, nrows)
   254  			if err != nil {
   255  				t.Fatalf("table.Read: %v", err)
   256  			}
   257  			count := int64(0)
   258  			for rows.Next() {
   259  				ref := make([]interface{}, len(table.tuple[i][count]))
   260  				data := make([]interface{}, len(ref))
   261  				for ii, vv := range table.tuple[i][count] {
   262  					rt := reflect.TypeOf(vv)
   263  					rv := reflect.New(rt)
   264  					xx := rv.Interface()
   265  					data[ii] = xx
   266  					ref[ii] = vv
   267  				}
   268  				err = rows.Scan(data...)
   269  				if err != nil {
   270  					t.Fatalf("rows.Scan: %v", err)
   271  				}
   272  				// check data just read in is ok
   273  				// check columns data is ok
   274  				for ii, vv := range data {
   275  					rv := reflect.ValueOf(vv).Elem().Interface()
   276  					if !reflect.DeepEqual(rv, hdu.Col(ii).Value) {
   277  						t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", hdu.Col(ii).Value, rv)
   278  					}
   279  					if !reflect.DeepEqual(rv, ref[ii]) {
   280  						t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", ref[ii], rv)
   281  					}
   282  				}
   283  				// modify value of first column
   284  				switch vv := hdu.Col(0).Value.(type) {
   285  				case float64:
   286  					hdu.Col(0).Value = 1 + vv
   287  				case int16:
   288  					hdu.Col(0).Value = 1 + vv
   289  				}
   290  				// check data just read in is ok
   291  				// check columns data is ok
   292  				for ii, vv := range data {
   293  					if ii == 0 {
   294  						continue
   295  					}
   296  					rv := reflect.ValueOf(vv).Elem().Interface()
   297  					if !reflect.DeepEqual(rv, hdu.Col(ii).Value) {
   298  						t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", hdu.Col(ii).Value, rv)
   299  					}
   300  					if !reflect.DeepEqual(rv, ref[ii]) {
   301  						t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", ref[ii], rv)
   302  					}
   303  				}
   304  				// but column data has changed
   305  				if reflect.DeepEqual(reflect.ValueOf(data[0]).Elem().Interface(), hdu.Col(0).Value) {
   306  					t.Fatalf("expected different values!")
   307  				}
   308  				count++
   309  			}
   310  			err = rows.Err()
   311  			if err != nil {
   312  				t.Fatalf("rows.Err: %v", err)
   313  			}
   314  			if count != nrows {
   315  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows, count)
   316  			}
   317  		}
   318  	}
   319  }
   320  
   321  func TestTableScanMap(t *testing.T) {
   322  	for _, table := range g_tables {
   323  		fname := table.fname
   324  		f, err := Open(fname, ReadOnly)
   325  		if err != nil {
   326  			t.Fatalf("error opening file [%v]: %v", fname, err)
   327  		}
   328  
   329  		for i := range f.HDUs() {
   330  			hdu, ok := f.HDU(i).(*Table)
   331  			if !ok {
   332  				continue
   333  			}
   334  			refmap := table.maps[i]
   335  			if len(refmap) <= 0 {
   336  				continue
   337  			}
   338  			nrows := hdu.NumRows()
   339  			rows, err := hdu.Read(0, nrows)
   340  			if err != nil {
   341  				t.Fatalf("table.Read: %v", err)
   342  			}
   343  			count := int64(0)
   344  			for rows.Next() {
   345  				ref := make(map[string]interface{}, len(refmap))
   346  				data := make(map[string]interface{}, len(refmap))
   347  				for kk, vv := range table.maps[i] {
   348  					rt := reflect.TypeOf(vv)
   349  					rv := reflect.New(rt)
   350  					xx := rv.Interface()
   351  					data[kk] = xx
   352  					ii := hdu.Index(kk)
   353  					if ii < 0 {
   354  						t.Fatalf("could not find index of [%v]", kk)
   355  					}
   356  					ref[kk] = table.tuple[i][count][ii]
   357  				}
   358  				err = rows.Scan(&data)
   359  				if err != nil {
   360  					t.Fatalf("rows.Scan: %v", err)
   361  				}
   362  				// check data just read in is ok
   363  				if !reflect.DeepEqual(data, ref) {
   364  					t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", ref, data)
   365  				}
   366  				// check columns data is ok
   367  				for kk, vv := range data {
   368  					ii := hdu.Index(kk)
   369  					if !reflect.DeepEqual(vv, hdu.Col(ii).Value) {
   370  						t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", hdu.Col(ii).Value, vv)
   371  					}
   372  				}
   373  				// modify value of first column
   374  				kk := hdu.Col(0).Name
   375  				switch vv := hdu.Col(0).Value.(type) {
   376  				case float64:
   377  					hdu.Col(0).Value = 1 + vv
   378  				case int16:
   379  					hdu.Col(0).Value = 1 + vv
   380  				}
   381  				// check data is still ok
   382  				if !reflect.DeepEqual(data, ref) {
   383  					t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", ref, data)
   384  				}
   385  				// but column data has changed
   386  				if reflect.DeepEqual(data[kk], hdu.Col(0).Value) {
   387  					t.Fatalf("expected different values!")
   388  				}
   389  				count++
   390  			}
   391  			err = rows.Err()
   392  			if err != nil {
   393  				t.Fatalf("rows.Err: %v", err)
   394  			}
   395  			if count != nrows {
   396  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows, count)
   397  			}
   398  		}
   399  	}
   400  }
   401  
   402  func TestTableScanStruct(t *testing.T) {
   403  	for _, table := range g_tables {
   404  		fname := table.fname
   405  		f, err := Open(fname, ReadOnly)
   406  		if err != nil {
   407  			t.Fatalf("error opening file [%v]: %v", fname, err)
   408  		}
   409  
   410  		for i := range f.HDUs() {
   411  			hdu, ok := f.HDU(i).(*Table)
   412  			if !ok {
   413  				continue
   414  			}
   415  			reftypes := table.types[i]
   416  			if reftypes == nil {
   417  				continue
   418  			}
   419  			reftype := reflect.TypeOf(reftypes)
   420  			nrows := hdu.NumRows()
   421  			rows, err := hdu.Read(0, nrows)
   422  			if err != nil {
   423  				t.Fatalf("table.Read: %v", err)
   424  			}
   425  			count := int64(0)
   426  			for rows.Next() {
   427  				ref := reflect.New(reftype)
   428  				data := reflect.New(reftype)
   429  				for ii := 0; ii < reftype.NumField(); ii++ {
   430  					ft := reftype.Field(ii)
   431  					kk := ft.Tag.Get("fits")
   432  					if kk == "" {
   433  						kk = ft.Name
   434  					}
   435  					idx := hdu.Index(kk)
   436  					if idx < 0 {
   437  						t.Fatalf("could not find index of [%v.%v]", reftype.Name(), ft.Name)
   438  					}
   439  					vv := reflect.ValueOf(table.tuple[i][count][idx])
   440  					reflect.Indirect(ref).Field(ii).Set(vv)
   441  				}
   442  
   443  				err = rows.Scan(data.Interface())
   444  				if err != nil {
   445  					t.Fatalf("rows.Scan: %v", err)
   446  				}
   447  				// check data just read in is ok
   448  				if !reflect.DeepEqual(data.Interface(), ref.Interface()) {
   449  					t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", ref, data)
   450  				}
   451  				// check columns data is ok
   452  				for ii := 0; ii < reftype.NumField(); ii++ {
   453  					ft := reftype.Field(ii)
   454  					kk := ft.Tag.Get("fits")
   455  					if kk == "" {
   456  						kk = ft.Name
   457  					}
   458  					idx := hdu.Index(kk)
   459  					if idx < 0 {
   460  						t.Fatalf("could not find index of [%v.%v]", reftype.Name(), ft.Name)
   461  					}
   462  					vv := data.Elem().Field(ii).Interface()
   463  					if !reflect.DeepEqual(vv, hdu.Col(idx).Value) {
   464  						t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", hdu.Col(idx).Value, vv)
   465  					}
   466  				}
   467  				// modify value of first column
   468  				switch vv := hdu.Col(0).Value.(type) {
   469  				case float64:
   470  					hdu.Col(0).Value = 1 + vv
   471  				case int16:
   472  					hdu.Col(0).Value = 1 + vv
   473  				}
   474  				// check data is still ok
   475  				if !reflect.DeepEqual(data.Interface(), ref.Interface()) {
   476  					t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v", ref, data)
   477  				}
   478  				// but column data has changed
   479  				if reflect.DeepEqual(data.Elem().Field(0).Interface(), hdu.Col(0).Value) {
   480  					t.Fatalf("expected different values!")
   481  				}
   482  				count++
   483  			}
   484  			err = rows.Err()
   485  			if err != nil {
   486  				t.Fatalf("rows.Err: %v", err)
   487  			}
   488  			if count != nrows {
   489  				t.Fatalf("rows.Next: expected [%d] rows. got %d.", nrows, count)
   490  			}
   491  		}
   492  	}
   493  }
   494  
   495  func TestTableBuiltinsRW(t *testing.T) {
   496  
   497  	curdir, err := os.Getwd()
   498  	if err != nil {
   499  		t.Fatalf(err.Error())
   500  	}
   501  	defer os.Chdir(curdir)
   502  
   503  	workdir, err := ioutil.TempDir("", "go-cfitsio-test-")
   504  	if err != nil {
   505  		t.Fatalf(err.Error())
   506  	}
   507  	defer os.RemoveAll(workdir)
   508  
   509  	err = os.Chdir(workdir)
   510  	if err != nil {
   511  		t.Fatalf(err.Error())
   512  	}
   513  
   514  	for ii, table := range []struct {
   515  		name  string
   516  		cols  []Column
   517  		htype HDUType
   518  		table interface{}
   519  	}{
   520  		{
   521  			name: "new.fits",
   522  			cols: []Column{
   523  				{
   524  					Name:  "int8s",
   525  					Value: int8(42),
   526  				},
   527  			},
   528  			htype: ASCII_TBL,
   529  			table: []int8{
   530  				10, 11, 12, 13,
   531  				14, 15, 16, 17,
   532  				18, 19, 10, 11,
   533  			},
   534  		},
   535  		{
   536  			name: "new.fits",
   537  			cols: []Column{
   538  				{
   539  					Name:  "int16s",
   540  					Value: int16(42),
   541  				},
   542  			},
   543  			htype: ASCII_TBL,
   544  			table: []int16{
   545  				10, 11, 12, 13,
   546  				14, 15, 16, 17,
   547  				18, 19, 10, 11,
   548  			},
   549  		},
   550  		{
   551  			name: "new.fits",
   552  			cols: []Column{
   553  				{
   554  					Name:  "int32s",
   555  					Value: int32(42),
   556  				},
   557  			},
   558  			htype: ASCII_TBL,
   559  			table: []int32{
   560  				10, 11, 12, 13,
   561  				14, 15, 16, 17,
   562  				18, 19, 10, 11,
   563  			},
   564  		},
   565  		{
   566  			name: "new.fits",
   567  			cols: []Column{
   568  				{
   569  					Name:  "int64s",
   570  					Value: int64(42),
   571  				},
   572  			},
   573  			htype: ASCII_TBL,
   574  			table: []int64{
   575  				10, 11, 12, 13,
   576  				14, 15, 16, 17,
   577  				18, 19, 10, 11,
   578  			},
   579  		},
   580  		{
   581  			name: "new.fits",
   582  			cols: []Column{
   583  				{
   584  					Name:  "ints",
   585  					Value: int(42),
   586  				},
   587  			},
   588  			htype: ASCII_TBL,
   589  			table: []int{
   590  				10, 11, 12, 13,
   591  				14, 15, 16, 17,
   592  				18, 19, 10, 11,
   593  			},
   594  		},
   595  		{
   596  			name: "new.fits",
   597  			cols: []Column{
   598  				{
   599  					Name:  "uint8s",
   600  					Value: uint8(42),
   601  				},
   602  			},
   603  			htype: ASCII_TBL,
   604  			table: []uint8{
   605  				10, 11, 12, 13,
   606  				14, 15, 16, 17,
   607  				18, 19, 10, 11,
   608  			},
   609  		},
   610  		{
   611  			name: "new.fits",
   612  			cols: []Column{
   613  				{
   614  					Name:  "uint16s",
   615  					Value: uint16(42),
   616  				},
   617  			},
   618  			htype: ASCII_TBL,
   619  			table: []uint16{
   620  				10, 11, 12, 13,
   621  				14, 15, 16, 17,
   622  				18, 19, 10, 11,
   623  			},
   624  		},
   625  		{
   626  			name: "new.fits",
   627  			cols: []Column{
   628  				{
   629  					Name:  "uint32s",
   630  					Value: uint32(42),
   631  				},
   632  			},
   633  			htype: ASCII_TBL,
   634  			table: []uint32{
   635  				10, 11, 12, 13,
   636  				14, 15, 16, 17,
   637  				18, 19, 10, 11,
   638  			},
   639  		},
   640  		{
   641  			name: "new.fits",
   642  			cols: []Column{
   643  				{
   644  					Name:  "uint64s",
   645  					Value: uint64(42),
   646  				},
   647  			},
   648  			htype: ASCII_TBL,
   649  			table: []uint64{
   650  				10, 11, 12, 13,
   651  				14, 15, 16, 17,
   652  				18, 19, 10, 11,
   653  			},
   654  		},
   655  		{
   656  			name: "new.fits",
   657  			cols: []Column{
   658  				{
   659  					Name:  "uints",
   660  					Value: uint(42),
   661  				},
   662  			},
   663  			htype: ASCII_TBL,
   664  			table: []uint{
   665  				10, 11, 12, 13,
   666  				14, 15, 16, 17,
   667  				18, 19, 10, 11,
   668  			},
   669  		},
   670  		{
   671  			name: "new.fits",
   672  			cols: []Column{
   673  				{
   674  					Name:  "float32s",
   675  					Value: float32(42),
   676  				},
   677  			},
   678  			htype: ASCII_TBL,
   679  			table: []float32{
   680  				10, 11, 12, 13,
   681  				14, 15, 16, 17,
   682  				18, 19, 10, 11,
   683  			},
   684  		},
   685  		{
   686  			name: "new.fits",
   687  			cols: []Column{
   688  				{
   689  					Name:  "float64s",
   690  					Value: float64(42),
   691  				},
   692  			},
   693  			htype: ASCII_TBL,
   694  			table: []float64{
   695  				10, 11, 12, 13,
   696  				14, 15, 16, 17,
   697  				18, 19, 10, 11,
   698  			},
   699  		},
   700  		{
   701  			name: "new.fits",
   702  			cols: []Column{
   703  				{
   704  					Name:  "strings",
   705  					Value: "",
   706  				},
   707  			},
   708  			htype: ASCII_TBL,
   709  			table: []string{
   710  				"10", "11", "12", "13",
   711  				"14", "15", "16", "17",
   712  				"18", "19", "10", "11",
   713  			},
   714  		},
   715  		// binary table
   716  		{
   717  			name: "new.fits",
   718  			cols: []Column{
   719  				{
   720  					Name:  "bools",
   721  					Value: false,
   722  				},
   723  			},
   724  			htype: BINARY_TBL,
   725  			table: []bool{
   726  				true, true, true, true,
   727  				false, false, false, false,
   728  				true, false, true, false,
   729  				false, true, false, true,
   730  			},
   731  		},
   732  		{
   733  			name: "new.fits",
   734  			cols: []Column{
   735  				{
   736  					Name:  "int8s",
   737  					Value: int8(42),
   738  				},
   739  			},
   740  			htype: BINARY_TBL,
   741  			table: []int8{
   742  				10, 11, 12, 13,
   743  				14, 15, 16, 17,
   744  				18, 19, 10, 11,
   745  			},
   746  		},
   747  		{
   748  			name: "new.fits",
   749  			cols: []Column{
   750  				{
   751  					Name:  "int16s",
   752  					Value: int16(42),
   753  				},
   754  			},
   755  			htype: BINARY_TBL,
   756  			table: []int16{
   757  				10, 11, 12, 13,
   758  				14, 15, 16, 17,
   759  				18, 19, 10, 11,
   760  			},
   761  		},
   762  		{
   763  			name: "new.fits",
   764  			cols: []Column{
   765  				{
   766  					Name:  "int32s",
   767  					Value: int32(42),
   768  				},
   769  			},
   770  			htype: BINARY_TBL,
   771  			table: []int32{
   772  				10, 11, 12, 13,
   773  				14, 15, 16, 17,
   774  				18, 19, 10, 11,
   775  			},
   776  		},
   777  		{
   778  			name: "new.fits",
   779  			cols: []Column{
   780  				{
   781  					Name:  "int64s",
   782  					Value: int64(42),
   783  				},
   784  			},
   785  			htype: BINARY_TBL,
   786  			table: []int64{
   787  				10, 11, 12, 13,
   788  				14, 15, 16, 17,
   789  				18, 19, 10, 11,
   790  			},
   791  		},
   792  		{
   793  			name: "new.fits",
   794  			cols: []Column{
   795  				{
   796  					Name:  "ints",
   797  					Value: int(42),
   798  				},
   799  			},
   800  			htype: BINARY_TBL,
   801  			table: []int{
   802  				10, 11, 12, 13,
   803  				14, 15, 16, 17,
   804  				18, 19, 10, 11,
   805  			},
   806  		},
   807  		{
   808  			name: "new.fits",
   809  			cols: []Column{
   810  				{
   811  					Name:  "uint8s",
   812  					Value: uint8(42),
   813  				},
   814  			},
   815  			htype: BINARY_TBL,
   816  			table: []uint8{
   817  				10, 11, 12, 13,
   818  				14, 15, 16, 17,
   819  				18, 19, 10, 11,
   820  			},
   821  		},
   822  		{
   823  			name: "new.fits",
   824  			cols: []Column{
   825  				{
   826  					Name:  "uint16s",
   827  					Value: uint16(42),
   828  				},
   829  			},
   830  			htype: BINARY_TBL,
   831  			table: []uint16{
   832  				10, 11, 12, 13,
   833  				14, 15, 16, 17,
   834  				18, 19, 10, 11,
   835  			},
   836  		},
   837  		{
   838  			name: "new.fits",
   839  			cols: []Column{
   840  				{
   841  					Name:  "uint32s",
   842  					Value: uint32(42),
   843  				},
   844  			},
   845  			htype: BINARY_TBL,
   846  			table: []uint32{
   847  				10, 11, 12, 13,
   848  				14, 15, 16, 17,
   849  				18, 19, 10, 11,
   850  			},
   851  		},
   852  		{
   853  			name: "new.fits",
   854  			cols: []Column{
   855  				{
   856  					Name:  "uint64s",
   857  					Value: uint64(42),
   858  				},
   859  			},
   860  			htype: BINARY_TBL,
   861  			table: []uint64{
   862  				10, 11, 12, 13,
   863  				14, 15, 16, 17,
   864  				18, 19, 10, 11,
   865  			},
   866  		},
   867  		{
   868  			name: "new.fits",
   869  			cols: []Column{
   870  				{
   871  					Name:  "uints",
   872  					Value: uint(42),
   873  				},
   874  			},
   875  			htype: BINARY_TBL,
   876  			table: []uint{
   877  				10, 11, 12, 13,
   878  				14, 15, 16, 17,
   879  				18, 19, 10, 11,
   880  			},
   881  		},
   882  		{
   883  			name: "new.fits",
   884  			cols: []Column{
   885  				{
   886  					Name:  "float32s",
   887  					Value: float32(42),
   888  				},
   889  			},
   890  			htype: BINARY_TBL,
   891  			table: []float32{
   892  				10, 11, 12, 13,
   893  				14, 15, 16, 17,
   894  				18, 19, 10, 11,
   895  			},
   896  		},
   897  		{
   898  			name: "new.fits",
   899  			cols: []Column{
   900  				{
   901  					Name:  "float64s",
   902  					Value: float64(42),
   903  				},
   904  			},
   905  			htype: BINARY_TBL,
   906  			table: []float64{
   907  				10, 11, 12, 13,
   908  				14, 15, 16, 17,
   909  				18, 19, 10, 11,
   910  			},
   911  		},
   912  		{
   913  			name: "new.fits",
   914  			cols: []Column{
   915  				{
   916  					Name:  "cplx64s",
   917  					Value: complex(float32(42), float32(42)),
   918  				},
   919  			},
   920  			htype: BINARY_TBL,
   921  			table: []complex64{
   922  				complex(float32(10), float32(10)), complex(float32(11), float32(11)),
   923  				complex(float32(12), float32(12)), complex(float32(13), float32(13)),
   924  				complex(float32(14), float32(14)), complex(float32(15), float32(15)),
   925  				complex(float32(16), float32(16)), complex(float32(17), float32(17)),
   926  				complex(float32(18), float32(18)), complex(float32(19), float32(19)),
   927  				complex(float32(10), float32(10)), complex(float32(11), float32(11)),
   928  			},
   929  		},
   930  		{
   931  			name: "new.fits",
   932  			cols: []Column{
   933  				{
   934  					Name:  "cplx128s",
   935  					Value: complex(float64(42), float64(42)),
   936  				},
   937  			},
   938  			htype: BINARY_TBL,
   939  			table: []complex128{
   940  				complex(10, 10), complex(11, 11), complex(12, 12), complex(13, 13),
   941  				complex(14, 14), complex(15, 15), complex(16, 16), complex(17, 17),
   942  				complex(18, 18), complex(19, 19), complex(10, 10), complex(11, 11),
   943  			},
   944  		},
   945  		{
   946  			name: "new.fits",
   947  			cols: []Column{
   948  				{
   949  					Name:  "strings",
   950  					Value: "",
   951  				},
   952  			},
   953  			htype: BINARY_TBL,
   954  			table: []string{
   955  				"10", "11", "12", "13",
   956  				"14", "15", "16", "17",
   957  				"18", "19", "10", "11",
   958  			},
   959  		},
   960  		{
   961  			name: "new.fits",
   962  			cols: []Column{
   963  				{
   964  					Name:  "float64s",
   965  					Value: [2]float64{},
   966  				},
   967  			},
   968  			htype: BINARY_TBL,
   969  			table: [][2]float64{
   970  				{10, 11},
   971  				{12, 13},
   972  				{14, 15},
   973  				{16, 17},
   974  				{18, 19},
   975  				{10, 11},
   976  			},
   977  		},
   978  	} {
   979  		fname := fmt.Sprintf("%03d_%s", ii, table.name)
   980  		for _, fct := range []func(){
   981  			// create
   982  			func() {
   983  				f, err := Create(fname)
   984  				if err != nil {
   985  					t.Fatalf("error creating new file [%v]: %v", fname, err)
   986  				}
   987  				defer f.Close()
   988  
   989  				phdu, err := NewPrimaryHDU(&f, NewDefaultHeader())
   990  				if err != nil {
   991  					t.Fatalf("error creating PHDU: %v", err)
   992  				}
   993  				defer phdu.Close()
   994  
   995  				tbl, err := NewTable(&f, "test", table.cols, table.htype)
   996  				if err != nil {
   997  					t.Fatalf("error creating new table: %v (%v)", err, table.cols[0].Name)
   998  				}
   999  				defer tbl.Close()
  1000  
  1001  				rslice := reflect.ValueOf(table.table)
  1002  				for i := 0; i < rslice.Len(); i++ {
  1003  					data := rslice.Index(i).Addr()
  1004  					err = tbl.Write(data.Interface())
  1005  					if err != nil {
  1006  						t.Fatalf("error writing row [%v]: %v (data=%v %T)", i, err, data.Interface(), data.Interface())
  1007  					}
  1008  				}
  1009  
  1010  				nrows := tbl.NumRows()
  1011  				if nrows != int64(rslice.Len()) {
  1012  					t.Fatalf("expected num rows [%v]. got [%v] (%v)", rslice.Len(), nrows, table.cols[0].Name)
  1013  				}
  1014  			},
  1015  			// read
  1016  			func() {
  1017  				f, err := Open(fname, ReadOnly)
  1018  				if err != nil {
  1019  					t.Fatalf("error opening file [%v]: %v", fname, err)
  1020  				}
  1021  				defer f.Close()
  1022  
  1023  				hdu := f.HDU(1)
  1024  				tbl := hdu.(*Table)
  1025  				if tbl.Name() != "test" {
  1026  					t.Fatalf("expected table name==%q. got %q", "test", tbl.Name())
  1027  				}
  1028  
  1029  				rslice := reflect.ValueOf(table.table)
  1030  				nrows := tbl.NumRows()
  1031  				if nrows != int64(rslice.Len()) {
  1032  					t.Fatalf("expected num rows [%v]. got [%v]", rslice.Len(), nrows)
  1033  				}
  1034  
  1035  				rows, err := tbl.Read(0, nrows)
  1036  				if err != nil {
  1037  					t.Fatalf("table.Read: %v", err)
  1038  				}
  1039  				count := int64(0)
  1040  				for rows.Next() {
  1041  					ref := rslice.Index(int(count)).Interface()
  1042  					rt := reflect.TypeOf(ref)
  1043  					data := reflect.New(rt).Elem().Interface()
  1044  					err = rows.Scan(&data)
  1045  					if err != nil {
  1046  						t.Fatalf("rows.Scan: %v", err)
  1047  					}
  1048  					// check data just read in is ok
  1049  					if !reflect.DeepEqual(data, ref) {
  1050  						t.Fatalf("rows.Scan: %[3]s\nexp=%[1]v (%[1]T)\ngot=%[2]v (%[2]T)", ref, data, table.cols[0].Name)
  1051  					}
  1052  					count++
  1053  				}
  1054  				if count != nrows {
  1055  					t.Fatalf("expected [%v] rows. got [%v]", nrows, count)
  1056  				}
  1057  			},
  1058  		} {
  1059  			fct()
  1060  		}
  1061  	}
  1062  }
  1063  
  1064  func TestTableSliceRW(t *testing.T) {
  1065  
  1066  	curdir, err := os.Getwd()
  1067  	if err != nil {
  1068  		t.Fatalf(err.Error())
  1069  	}
  1070  	defer os.Chdir(curdir)
  1071  
  1072  	workdir, err := ioutil.TempDir("", "go-cfitsio-test-")
  1073  	if err != nil {
  1074  		t.Fatalf(err.Error())
  1075  	}
  1076  	defer os.RemoveAll(workdir)
  1077  
  1078  	err = os.Chdir(workdir)
  1079  	if err != nil {
  1080  		t.Fatalf(err.Error())
  1081  	}
  1082  
  1083  	for ii, table := range []struct {
  1084  		name  string
  1085  		cols  []Column
  1086  		htype HDUType
  1087  		table interface{}
  1088  	}{
  1089  		// binary table
  1090  		{
  1091  			name: "new.fits",
  1092  			cols: []Column{
  1093  				{
  1094  					Name:  "bools",
  1095  					Value: []bool{},
  1096  				},
  1097  			},
  1098  			htype: BINARY_TBL,
  1099  			table: [][]bool{
  1100  				{true, true, true, true},
  1101  				{false, false, false, false},
  1102  				{true, false, true, false},
  1103  				{false, true, false, true},
  1104  			},
  1105  		},
  1106  		{
  1107  			name: "new.fits",
  1108  			cols: []Column{
  1109  				{
  1110  					Name:  "int8s",
  1111  					Value: []int8{},
  1112  				},
  1113  			},
  1114  			htype: BINARY_TBL,
  1115  			table: [][]int8{
  1116  				{10, 11, 12, 13},
  1117  				{14, 15, 16, 17},
  1118  				{18, 19, 10, 11},
  1119  			},
  1120  		},
  1121  		{
  1122  			name: "new.fits",
  1123  			cols: []Column{
  1124  				{
  1125  					Name:  "int16s",
  1126  					Value: []int16{},
  1127  				},
  1128  			},
  1129  			htype: BINARY_TBL,
  1130  			table: [][]int16{
  1131  				{10, 11, 12, 13},
  1132  				{14, 15, 16, 17},
  1133  				{18, 19, 10, 11},
  1134  			},
  1135  		},
  1136  		{
  1137  			name: "new.fits",
  1138  			cols: []Column{
  1139  				{
  1140  					Name:  "int32s",
  1141  					Value: []int32{},
  1142  				},
  1143  			},
  1144  			htype: BINARY_TBL,
  1145  			table: [][]int32{
  1146  				{10, 11, 12, 13},
  1147  				{14, 15, 16, 17},
  1148  				{18, 19, 10, 11},
  1149  			},
  1150  		},
  1151  		{
  1152  			name: "new.fits",
  1153  			cols: []Column{
  1154  				{
  1155  					Name:  "int64s",
  1156  					Value: []int64{},
  1157  				},
  1158  			},
  1159  			htype: BINARY_TBL,
  1160  			table: [][]int64{
  1161  				{10, 11, 12, 13},
  1162  				{14, 15, 16, 17},
  1163  				{18, 19, 10, 11},
  1164  			},
  1165  		},
  1166  		{
  1167  			name: "new.fits",
  1168  			cols: []Column{
  1169  				{
  1170  					Name:  "ints",
  1171  					Value: []int{},
  1172  				},
  1173  			},
  1174  			htype: BINARY_TBL,
  1175  			table: [][]int{
  1176  				{10, 11, 12, 13},
  1177  				{14, 15, 16, 17},
  1178  				{18, 19, 10, 11},
  1179  			},
  1180  		},
  1181  		{
  1182  			name: "new.fits",
  1183  			cols: []Column{
  1184  				{
  1185  					Name:  "uint8s",
  1186  					Value: []uint8{},
  1187  				},
  1188  			},
  1189  			htype: BINARY_TBL,
  1190  			table: [][]uint8{
  1191  				{10, 11, 12, 13},
  1192  				{14, 15, 16, 17},
  1193  				{18, 19, 10, 11},
  1194  			},
  1195  		},
  1196  		{
  1197  			name: "new.fits",
  1198  			cols: []Column{
  1199  				{
  1200  					Name:  "uint16s",
  1201  					Value: []uint16{},
  1202  				},
  1203  			},
  1204  			htype: BINARY_TBL,
  1205  			table: [][]uint16{
  1206  				{10, 11, 12, 13},
  1207  				{14, 15, 16, 17},
  1208  				{18, 19, 10, 11},
  1209  			},
  1210  		},
  1211  		{
  1212  			name: "new.fits",
  1213  			cols: []Column{
  1214  				{
  1215  					Name:  "uint32s",
  1216  					Value: []uint32{},
  1217  				},
  1218  			},
  1219  			htype: BINARY_TBL,
  1220  			table: [][]uint32{
  1221  				{10, 11, 12, 13},
  1222  				{14, 15, 16, 17},
  1223  				{18, 19, 10, 11},
  1224  			},
  1225  		},
  1226  		{
  1227  			name: "new.fits",
  1228  			cols: []Column{
  1229  				{
  1230  					Name:  "uint64s",
  1231  					Value: []uint64{},
  1232  				},
  1233  			},
  1234  			htype: BINARY_TBL,
  1235  			table: [][]uint64{
  1236  				{10, 11, 12, 13},
  1237  				{14, 15, 16, 17},
  1238  				{18, 19, 10, 11},
  1239  			},
  1240  		},
  1241  		{
  1242  			name: "new.fits",
  1243  			cols: []Column{
  1244  				{
  1245  					Name:  "uints",
  1246  					Value: []uint{},
  1247  				},
  1248  			},
  1249  			htype: BINARY_TBL,
  1250  			table: [][]uint{
  1251  				{10, 11, 12, 13},
  1252  				{14, 15, 16, 17},
  1253  				{18, 19, 10, 11},
  1254  			},
  1255  		},
  1256  		{
  1257  			name: "new.fits",
  1258  			cols: []Column{
  1259  				{
  1260  					Name:  "float32s",
  1261  					Value: []float32{},
  1262  				},
  1263  			},
  1264  			htype: BINARY_TBL,
  1265  			table: [][]float32{
  1266  				{10, 11, 12, 13},
  1267  				{14, 15, 16, 17},
  1268  				{18, 19, 10, 11},
  1269  			},
  1270  		},
  1271  		{
  1272  			name: "new.fits",
  1273  			cols: []Column{
  1274  				{
  1275  					Name:  "float64s",
  1276  					Value: []float64{},
  1277  				},
  1278  			},
  1279  			htype: BINARY_TBL,
  1280  			table: [][]float64{
  1281  				{10, 11, 12, 13},
  1282  				{14, 15, 16, 17},
  1283  				{18, 19, 10, 11},
  1284  			},
  1285  		},
  1286  		{
  1287  			name: "new.fits",
  1288  			cols: []Column{
  1289  				{
  1290  					Name:  "cplx64s",
  1291  					Value: []complex64{},
  1292  				},
  1293  			},
  1294  			htype: BINARY_TBL,
  1295  			table: [][]complex64{
  1296  				{complex(float32(10), float32(10)), complex(float32(11), float32(11)),
  1297  					complex(float32(12), float32(12)), complex(float32(13), float32(13))},
  1298  				{complex(float32(14), float32(14)), complex(float32(15), float32(15)),
  1299  					complex(float32(16), float32(16)), complex(float32(17), float32(17))},
  1300  				{complex(float32(18), float32(18)), complex(float32(19), float32(19)),
  1301  					complex(float32(10), float32(10)), complex(float32(11), float32(11))},
  1302  			},
  1303  		},
  1304  		{
  1305  			name: "new.fits",
  1306  			cols: []Column{
  1307  				{
  1308  					Name:  "cplx128s",
  1309  					Value: []complex128{},
  1310  				},
  1311  			},
  1312  			htype: BINARY_TBL,
  1313  			table: [][]complex128{
  1314  				{complex(10, 10), complex(11, 11), complex(12, 12), complex(13, 13)},
  1315  				{complex(14, 14), complex(15, 15), complex(16, 16), complex(17, 17)},
  1316  				{complex(18, 18), complex(19, 19), complex(10, 10), complex(11, 11)},
  1317  			},
  1318  		},
  1319  	} {
  1320  		fname := fmt.Sprintf("%03d_%s", ii, table.name)
  1321  		for _, fct := range []func(){
  1322  			// create
  1323  			func() {
  1324  				f, err := Create(fname)
  1325  				if err != nil {
  1326  					t.Fatalf("error creating new file [%v]: %v", fname, err)
  1327  				}
  1328  				defer f.Close()
  1329  
  1330  				phdu, err := NewPrimaryHDU(&f, NewDefaultHeader())
  1331  				if err != nil {
  1332  					t.Fatalf("error creating PHDU: %v", err)
  1333  				}
  1334  				defer phdu.Close()
  1335  
  1336  				tbl, err := NewTable(&f, "test", table.cols, table.htype)
  1337  				if err != nil {
  1338  					t.Fatalf("error creating new table: %v (%v)", err, table.cols[0].Name)
  1339  				}
  1340  				defer tbl.Close()
  1341  
  1342  				rslice := reflect.ValueOf(table.table)
  1343  				for i := 0; i < rslice.Len(); i++ {
  1344  					data := rslice.Index(i).Addr()
  1345  					err = tbl.Write(data.Interface())
  1346  					if err != nil {
  1347  						t.Fatalf("error writing row [%v]: %v", i, err)
  1348  					}
  1349  				}
  1350  
  1351  				nrows := tbl.NumRows()
  1352  				if nrows != int64(rslice.Len()) {
  1353  					t.Fatalf("expected num rows [%v]. got [%v] (%v)", rslice.Len(), nrows, table.cols[0].Name)
  1354  				}
  1355  			},
  1356  			// read
  1357  			func() {
  1358  				f, err := Open(fname, ReadOnly)
  1359  				if err != nil {
  1360  					t.Fatalf("error opening file [%v]: %v", fname, err)
  1361  				}
  1362  				defer f.Close()
  1363  
  1364  				hdu := f.HDU(1)
  1365  				tbl := hdu.(*Table)
  1366  				if tbl.Name() != "test" {
  1367  					t.Fatalf("expected table name==%q. got %q", "test", tbl.Name())
  1368  				}
  1369  
  1370  				rslice := reflect.ValueOf(table.table)
  1371  				nrows := tbl.NumRows()
  1372  				if nrows != int64(rslice.Len()) {
  1373  					t.Fatalf("expected num rows [%v]. got [%v]", rslice.Len(), nrows)
  1374  				}
  1375  
  1376  				rows, err := tbl.Read(0, nrows)
  1377  				if err != nil {
  1378  					t.Fatalf("table.Read: %v", err)
  1379  				}
  1380  				count := int64(0)
  1381  				for rows.Next() {
  1382  					ref := rslice.Index(int(count)).Interface()
  1383  					rt := reflect.TypeOf(ref)
  1384  					data := reflect.New(rt).Elem().Interface()
  1385  					err = rows.Scan(&data)
  1386  					if err != nil {
  1387  						t.Fatalf("rows.Scan: %v", err)
  1388  					}
  1389  					// check data just read in is ok
  1390  					if !reflect.DeepEqual(data, ref) {
  1391  						t.Fatalf("rows.Scan: [%[3]s|%[4]v]\nexp=%[1]v (%[1]T)\ngot=%[2]v (%[2]T)", ref, data, table.cols[0].Name, table.htype)
  1392  					}
  1393  					count++
  1394  				}
  1395  				if count != nrows {
  1396  					t.Fatalf("expected [%v] rows. got [%v]", nrows, count)
  1397  				}
  1398  			},
  1399  		} {
  1400  			fct()
  1401  		}
  1402  	}
  1403  }
  1404  
  1405  func TestTableArrayRW(t *testing.T) {
  1406  
  1407  	curdir, err := os.Getwd()
  1408  	if err != nil {
  1409  		t.Fatalf(err.Error())
  1410  	}
  1411  	defer os.Chdir(curdir)
  1412  
  1413  	workdir, err := ioutil.TempDir("", "go-cfitsio-test-")
  1414  	if err != nil {
  1415  		t.Fatalf(err.Error())
  1416  	}
  1417  	defer os.RemoveAll(workdir)
  1418  
  1419  	err = os.Chdir(workdir)
  1420  	if err != nil {
  1421  		t.Fatalf(err.Error())
  1422  	}
  1423  
  1424  	for ii, table := range []struct {
  1425  		name  string
  1426  		cols  []Column
  1427  		htype HDUType
  1428  		table interface{}
  1429  	}{
  1430  		// binary table
  1431  		{
  1432  			name: "new.fits",
  1433  			cols: []Column{
  1434  				{
  1435  					Name:  "bools",
  1436  					Value: [4]bool{},
  1437  				},
  1438  			},
  1439  			htype: BINARY_TBL,
  1440  			table: [][4]bool{
  1441  				{true, true, true, true},
  1442  				{false, false, false, false},
  1443  				{true, false, true, false},
  1444  				{false, true, false, true},
  1445  			},
  1446  		},
  1447  		{
  1448  			name: "new.fits",
  1449  			cols: []Column{
  1450  				{
  1451  					Name:  "int8s",
  1452  					Value: [4]int8{},
  1453  				},
  1454  			},
  1455  			htype: BINARY_TBL,
  1456  			table: [][4]int8{
  1457  				{10, 11, 12, 13},
  1458  				{14, 15, 16, 17},
  1459  				{18, 19, 10, 11},
  1460  			},
  1461  		},
  1462  		{
  1463  			name: "new.fits",
  1464  			cols: []Column{
  1465  				{
  1466  					Name:  "int16s",
  1467  					Value: [4]int16{},
  1468  				},
  1469  			},
  1470  			htype: BINARY_TBL,
  1471  			table: [][4]int16{
  1472  				{10, 11, 12, 13},
  1473  				{14, 15, 16, 17},
  1474  				{18, 19, 10, 11},
  1475  			},
  1476  		},
  1477  		{
  1478  			name: "new.fits",
  1479  			cols: []Column{
  1480  				{
  1481  					Name:  "int32s",
  1482  					Value: [4]int32{},
  1483  				},
  1484  			},
  1485  			htype: BINARY_TBL,
  1486  			table: [][4]int32{
  1487  				{10, 11, 12, 13},
  1488  				{14, 15, 16, 17},
  1489  				{18, 19, 10, 11},
  1490  			},
  1491  		},
  1492  		{
  1493  			name: "new.fits",
  1494  			cols: []Column{
  1495  				{
  1496  					Name:  "int64s",
  1497  					Value: [4]int64{},
  1498  				},
  1499  			},
  1500  			htype: BINARY_TBL,
  1501  			table: [][4]int64{
  1502  				{10, 11, 12, 13},
  1503  				{14, 15, 16, 17},
  1504  				{18, 19, 10, 11},
  1505  			},
  1506  		},
  1507  		{
  1508  			name: "new.fits",
  1509  			cols: []Column{
  1510  				{
  1511  					Name:  "ints",
  1512  					Value: [4]int{},
  1513  				},
  1514  			},
  1515  			htype: BINARY_TBL,
  1516  			table: [][4]int{
  1517  				{10, 11, 12, 13},
  1518  				{14, 15, 16, 17},
  1519  				{18, 19, 10, 11},
  1520  			},
  1521  		},
  1522  		{
  1523  			name: "new.fits",
  1524  			cols: []Column{
  1525  				{
  1526  					Name:  "uint8s",
  1527  					Value: [4]uint8{},
  1528  				},
  1529  			},
  1530  			htype: BINARY_TBL,
  1531  			table: [][4]uint8{
  1532  				{10, 11, 12, 13},
  1533  				{14, 15, 16, 17},
  1534  				{18, 19, 10, 11},
  1535  			},
  1536  		},
  1537  		{
  1538  			name: "new.fits",
  1539  			cols: []Column{
  1540  				{
  1541  					Name:  "uint16s",
  1542  					Value: [4]uint16{},
  1543  				},
  1544  			},
  1545  			htype: BINARY_TBL,
  1546  			table: [][4]uint16{
  1547  				{10, 11, 12, 13},
  1548  				{14, 15, 16, 17},
  1549  				{18, 19, 10, 11},
  1550  			},
  1551  		},
  1552  		{
  1553  			name: "new.fits",
  1554  			cols: []Column{
  1555  				{
  1556  					Name:  "uint32s",
  1557  					Value: [4]uint32{},
  1558  				},
  1559  			},
  1560  			htype: BINARY_TBL,
  1561  			table: [][4]uint32{
  1562  				{10, 11, 12, 13},
  1563  				{14, 15, 16, 17},
  1564  				{18, 19, 10, 11},
  1565  			},
  1566  		},
  1567  		{
  1568  			name: "new.fits",
  1569  			cols: []Column{
  1570  				{
  1571  					Name:  "uint64s",
  1572  					Value: [4]uint64{},
  1573  				},
  1574  			},
  1575  			htype: BINARY_TBL,
  1576  			table: [][4]uint64{
  1577  				{10, 11, 12, 13},
  1578  				{14, 15, 16, 17},
  1579  				{18, 19, 10, 11},
  1580  			},
  1581  		},
  1582  		{
  1583  			name: "new.fits",
  1584  			cols: []Column{
  1585  				{
  1586  					Name:  "uints",
  1587  					Value: [4]uint{},
  1588  				},
  1589  			},
  1590  			htype: BINARY_TBL,
  1591  			table: [][4]uint{
  1592  				{10, 11, 12, 13},
  1593  				{14, 15, 16, 17},
  1594  				{18, 19, 10, 11},
  1595  			},
  1596  		},
  1597  		{
  1598  			name: "new.fits",
  1599  			cols: []Column{
  1600  				{
  1601  					Name:  "float32s",
  1602  					Value: [4]float32{},
  1603  				},
  1604  			},
  1605  			htype: BINARY_TBL,
  1606  			table: [][4]float32{
  1607  				{10, 11, 12, 13},
  1608  				{14, 15, 16, 17},
  1609  				{18, 19, 10, 11},
  1610  			},
  1611  		},
  1612  		{
  1613  			name: "new.fits",
  1614  			cols: []Column{
  1615  				{
  1616  					Name:  "float64s",
  1617  					Value: [4]float64{},
  1618  				},
  1619  			},
  1620  			htype: BINARY_TBL,
  1621  			table: [][4]float64{
  1622  				{10, 11, 12, 13},
  1623  				{14, 15, 16, 17},
  1624  				{18, 19, 10, 11},
  1625  			},
  1626  		},
  1627  		{
  1628  			name: "new.fits",
  1629  			cols: []Column{
  1630  				{
  1631  					Name:  "cplx64s",
  1632  					Value: [4]complex64{},
  1633  				},
  1634  			},
  1635  			htype: BINARY_TBL,
  1636  			table: [][4]complex64{
  1637  				{complex(float32(10), float32(10)), complex(float32(11), float32(11)),
  1638  					complex(float32(12), float32(12)), complex(float32(13), float32(13))},
  1639  				{complex(float32(14), float32(14)), complex(float32(15), float32(15)),
  1640  					complex(float32(16), float32(16)), complex(float32(17), float32(17))},
  1641  				{complex(float32(18), float32(18)), complex(float32(19), float32(19)),
  1642  					complex(float32(10), float32(10)), complex(float32(11), float32(11))},
  1643  			},
  1644  		},
  1645  		{
  1646  			name: "new.fits",
  1647  			cols: []Column{
  1648  				{
  1649  					Name:  "cplx128s",
  1650  					Value: [4]complex128{},
  1651  				},
  1652  			},
  1653  			htype: BINARY_TBL,
  1654  			table: [][4]complex128{
  1655  				{complex(10, 10), complex(11, 11), complex(12, 12), complex(13, 13)},
  1656  				{complex(14, 14), complex(15, 15), complex(16, 16), complex(17, 17)},
  1657  				{complex(18, 18), complex(19, 19), complex(10, 10), complex(11, 11)},
  1658  			},
  1659  		},
  1660  	} {
  1661  		fname := fmt.Sprintf("%03d_%s", ii, table.name)
  1662  		for _, fct := range []func(){
  1663  			// create
  1664  			func() {
  1665  				f, err := Create(fname)
  1666  				if err != nil {
  1667  					t.Fatalf("error creating new file [%v]: %v", fname, err)
  1668  				}
  1669  				defer f.Close()
  1670  
  1671  				phdu, err := NewPrimaryHDU(&f, NewDefaultHeader())
  1672  				if err != nil {
  1673  					t.Fatalf("error creating PHDU: %v", err)
  1674  				}
  1675  				defer phdu.Close()
  1676  
  1677  				tbl, err := NewTable(&f, "test", table.cols, table.htype)
  1678  				if err != nil {
  1679  					t.Fatalf("error creating new table: %v (%v)", err, table.cols[0].Name)
  1680  				}
  1681  				defer tbl.Close()
  1682  
  1683  				rslice := reflect.ValueOf(table.table)
  1684  				for i := 0; i < rslice.Len(); i++ {
  1685  					data := rslice.Index(i).Addr()
  1686  					err = tbl.Write(data.Interface())
  1687  					if err != nil {
  1688  						t.Fatalf("error writing row [%v]: %v", i, err)
  1689  					}
  1690  				}
  1691  
  1692  				nrows := tbl.NumRows()
  1693  				if nrows != int64(rslice.Len()) {
  1694  					t.Fatalf("expected num rows [%v]. got [%v] (%v)", rslice.Len(), nrows, table.cols[0].Name)
  1695  				}
  1696  			},
  1697  			// read
  1698  			func() {
  1699  				f, err := Open(fname, ReadOnly)
  1700  				if err != nil {
  1701  					t.Fatalf("error opening file [%v]: %v", fname, err)
  1702  				}
  1703  				defer f.Close()
  1704  
  1705  				hdu := f.HDU(1)
  1706  				tbl := hdu.(*Table)
  1707  				if tbl.Name() != "test" {
  1708  					t.Fatalf("expected table name==%q. got %q", "test", tbl.Name())
  1709  				}
  1710  
  1711  				rslice := reflect.ValueOf(table.table)
  1712  				nrows := tbl.NumRows()
  1713  				if nrows != int64(rslice.Len()) {
  1714  					t.Fatalf("expected num rows [%v]. got [%v]", rslice.Len(), nrows)
  1715  				}
  1716  
  1717  				rows, err := tbl.Read(0, nrows)
  1718  				if err != nil {
  1719  					t.Fatalf("table.Read: %v", err)
  1720  				}
  1721  				count := int64(0)
  1722  				for rows.Next() {
  1723  					ref := rslice.Index(int(count)).Interface()
  1724  					rt := reflect.TypeOf(ref)
  1725  					data := reflect.New(rt).Elem().Interface()
  1726  					err = rows.Scan(&data)
  1727  					if err != nil {
  1728  						t.Fatalf("rows.Scan: %v", err)
  1729  					}
  1730  					// check data just read in is ok
  1731  					if !reflect.DeepEqual(data, ref) {
  1732  						t.Fatalf("rows.Scan: [%[3]s|%[4]v]\nexp=%[1]v (%[1]T)\ngot=%[2]v (%[2]T)", ref, data, table.cols[0].Name, table.htype)
  1733  					}
  1734  					count++
  1735  				}
  1736  				if count != nrows {
  1737  					t.Fatalf("expected [%v] rows. got [%v]", nrows, count)
  1738  				}
  1739  			},
  1740  		} {
  1741  			fct()
  1742  		}
  1743  	}
  1744  }
  1745  
  1746  func TestTableStructsRW(t *testing.T) {
  1747  
  1748  	curdir, err := os.Getwd()
  1749  	if err != nil {
  1750  		t.Fatalf(err.Error())
  1751  	}
  1752  	defer os.Chdir(curdir)
  1753  
  1754  	workdir, err := ioutil.TempDir("", "go-cfitsio-test-")
  1755  	if err != nil {
  1756  		t.Fatalf(err.Error())
  1757  	}
  1758  	defer os.RemoveAll(workdir)
  1759  
  1760  	err = os.Chdir(workdir)
  1761  	if err != nil {
  1762  		t.Fatalf(err.Error())
  1763  	}
  1764  
  1765  	type DataStruct struct {
  1766  		A   int64      `fits:"int64"`
  1767  		XX0 int        // hole
  1768  		B   float64    `fits:"float64"`
  1769  		XX1 int        // hole
  1770  		C   []int64    `fits:"int64s"`
  1771  		XX2 int        // hole
  1772  		D   []float64  `fits:"float64s"`
  1773  		XX3 int        // hole
  1774  		E   [2]float64 `fits:"arrfloat64s"`
  1775  	}
  1776  
  1777  	for ii, table := range []struct {
  1778  		name  string
  1779  		cols  []Column
  1780  		htype HDUType
  1781  		table interface{}
  1782  	}{
  1783  		{
  1784  			name: "new.fits",
  1785  			cols: []Column{
  1786  				{
  1787  					Name:  "int64",
  1788  					Value: int64(0),
  1789  				},
  1790  				{
  1791  					Name:  "float64",
  1792  					Value: float64(0),
  1793  				},
  1794  				{
  1795  					Name:  "int64s",
  1796  					Value: []int64{},
  1797  				},
  1798  				{
  1799  					Name:  "float64s",
  1800  					Value: []float64{},
  1801  				},
  1802  				{
  1803  					Name:  "arrfloat64s",
  1804  					Value: [2]float64{},
  1805  				},
  1806  			},
  1807  			htype: BINARY_TBL,
  1808  			table: []DataStruct{
  1809  				{A: 10, B: 10, C: []int64{10, 10}, D: []float64{10, 10}, E: [2]float64{10, 10}},
  1810  				{A: 11, B: 11, C: []int64{11, 11}, D: []float64{11, 11}, E: [2]float64{11, 11}},
  1811  				{A: 12, B: 12, C: []int64{12, 12}, D: []float64{12, 12}, E: [2]float64{12, 12}},
  1812  				{A: 13, B: 13, C: []int64{13, 13}, D: []float64{13, 13}, E: [2]float64{13, 13}},
  1813  			},
  1814  		},
  1815  	} {
  1816  		fname := fmt.Sprintf("%03d_%s", ii, table.name)
  1817  		for _, fct := range []func(){
  1818  			// create
  1819  			func() {
  1820  				f, err := Create(fname)
  1821  				if err != nil {
  1822  					t.Fatalf("error creating new file [%v]: %v", fname, err)
  1823  				}
  1824  				defer f.Close()
  1825  
  1826  				phdu, err := NewPrimaryHDU(&f, NewDefaultHeader())
  1827  				if err != nil {
  1828  					t.Fatalf("error creating PHDU: %v", err)
  1829  				}
  1830  				defer phdu.Close()
  1831  
  1832  				tbl, err := NewTable(&f, "test", table.cols, table.htype)
  1833  				if err != nil {
  1834  					t.Fatalf("error creating new table: %v (%v)", err, table.cols[0].Name)
  1835  				}
  1836  				defer tbl.Close()
  1837  
  1838  				rslice := reflect.ValueOf(table.table)
  1839  				for i := 0; i < rslice.Len(); i++ {
  1840  					data := rslice.Index(i).Addr()
  1841  					err = tbl.Write(data.Interface())
  1842  					if err != nil {
  1843  						t.Fatalf("error writing row [%v]: %v", i, err)
  1844  					}
  1845  				}
  1846  
  1847  				nrows := tbl.NumRows()
  1848  				if nrows != int64(rslice.Len()) {
  1849  					t.Fatalf("expected num rows [%v]. got [%v] (%v)", rslice.Len(), nrows, table.cols[0].Name)
  1850  				}
  1851  			},
  1852  			// read
  1853  			func() {
  1854  				f, err := Open(fname, ReadOnly)
  1855  				if err != nil {
  1856  					t.Fatalf("error opening file [%v]: %v", fname, err)
  1857  				}
  1858  				defer f.Close()
  1859  
  1860  				hdu := f.HDU(1)
  1861  				tbl := hdu.(*Table)
  1862  				if tbl.Name() != "test" {
  1863  					t.Fatalf("expected table name==%q. got %q", "test", tbl.Name())
  1864  				}
  1865  
  1866  				rslice := reflect.ValueOf(table.table)
  1867  				nrows := tbl.NumRows()
  1868  				if nrows != int64(rslice.Len()) {
  1869  					t.Fatalf("expected num rows [%v]. got [%v]", rslice.Len(), nrows)
  1870  				}
  1871  
  1872  				rows, err := tbl.Read(0, nrows)
  1873  				if err != nil {
  1874  					t.Fatalf("table.Read: %v", err)
  1875  				}
  1876  				count := int64(0)
  1877  				for rows.Next() {
  1878  					ref := rslice.Index(int(count)).Interface()
  1879  					rt := reflect.TypeOf(ref)
  1880  					rv := reflect.New(rt).Elem()
  1881  					data := rv.Interface().(DataStruct)
  1882  					err = rows.Scan(&data)
  1883  					if err != nil {
  1884  						t.Fatalf("rows.Scan: %v", err)
  1885  					}
  1886  					// check data just read in is ok
  1887  					if !reflect.DeepEqual(data, ref) {
  1888  						t.Fatalf("rows.Scan:\nexpected=%v\ngot=%v (%T)", ref, data, data)
  1889  					}
  1890  					count++
  1891  				}
  1892  				if count != nrows {
  1893  					t.Fatalf("expected [%v] rows. got [%v]", nrows, count)
  1894  				}
  1895  			},
  1896  		} {
  1897  			fct()
  1898  		}
  1899  	}
  1900  }
  1901  
  1902  func TestTableMapsRW(t *testing.T) {
  1903  
  1904  	curdir, err := os.Getwd()
  1905  	if err != nil {
  1906  		t.Fatalf(err.Error())
  1907  	}
  1908  	defer os.Chdir(curdir)
  1909  
  1910  	workdir, err := ioutil.TempDir("", "go-cfitsio-test-")
  1911  	if err != nil {
  1912  		t.Fatalf(err.Error())
  1913  	}
  1914  	defer os.RemoveAll(workdir)
  1915  
  1916  	err = os.Chdir(workdir)
  1917  	if err != nil {
  1918  		t.Fatalf(err.Error())
  1919  	}
  1920  
  1921  	for ii, table := range []struct {
  1922  		name  string
  1923  		cols  []Column
  1924  		htype HDUType
  1925  		table interface{}
  1926  	}{
  1927  		{
  1928  			name: "new.fits",
  1929  			cols: []Column{
  1930  				{
  1931  					Name:  "A",
  1932  					Value: int64(0),
  1933  				},
  1934  				{
  1935  					Name:  "B",
  1936  					Value: float64(0),
  1937  				},
  1938  				{
  1939  					Name:  "C",
  1940  					Value: []int64{},
  1941  				},
  1942  				{
  1943  					Name:  "D",
  1944  					Value: []float64{},
  1945  				},
  1946  				// FIXME: re-add when reflect.ArrayOf is available
  1947  				// {
  1948  				// 	Name:  "E",
  1949  				// 	Value: [2]float64{},
  1950  				// },
  1951  			},
  1952  			htype: BINARY_TBL,
  1953  			table: []map[string]interface{}{
  1954  				{
  1955  					"A": int64(10),
  1956  					"B": float64(10),
  1957  					"C": []int64{10, 10},
  1958  					"D": []float64{10, 10},
  1959  					// FIXME: re-add when reflect.ArrayOf is available
  1960  					// "E": [2]float64{10, 10},
  1961  				},
  1962  				{
  1963  					"A": int64(11),
  1964  					"B": float64(11),
  1965  					"C": []int64{11, 11},
  1966  					"D": []float64{11, 11},
  1967  					// FIXME: re-add when reflect.ArrayOf is available
  1968  					// "E": [2]float64{11, 11},
  1969  				},
  1970  				{
  1971  					"A": int64(12),
  1972  					"B": float64(12),
  1973  					"C": []int64{12, 12},
  1974  					"D": []float64{12, 12},
  1975  					// FIXME: re-add when reflect.ArrayOf is available
  1976  					// "E": [2]float64{12, 12},
  1977  				},
  1978  				{
  1979  					"A": int64(13),
  1980  					"B": float64(13),
  1981  					"C": []int64{13, 13},
  1982  					"D": []float64{13, 13},
  1983  					// FIXME: re-add when reflect.ArrayOf is available
  1984  					// "E": [2]float64{13, 13},
  1985  				},
  1986  			},
  1987  		},
  1988  	} {
  1989  		fname := fmt.Sprintf("%03d_%s", ii, table.name)
  1990  		for _, fct := range []func(){
  1991  			// create
  1992  			func() {
  1993  				f, err := Create(fname)
  1994  				if err != nil {
  1995  					t.Fatalf("error creating new file [%v]: %v", fname, err)
  1996  				}
  1997  				defer f.Close()
  1998  
  1999  				phdu, err := NewPrimaryHDU(&f, NewDefaultHeader())
  2000  				if err != nil {
  2001  					t.Fatalf("error creating PHDU: %v", err)
  2002  				}
  2003  				defer phdu.Close()
  2004  
  2005  				tbl, err := NewTable(&f, "test", table.cols, table.htype)
  2006  				if err != nil {
  2007  					t.Fatalf("error creating new table: %v (%v)", err, table.cols[0].Name)
  2008  				}
  2009  				defer tbl.Close()
  2010  
  2011  				rslice := reflect.ValueOf(table.table)
  2012  				for i := 0; i < rslice.Len(); i++ {
  2013  					data := rslice.Index(i).Addr()
  2014  					err = tbl.Write(data.Interface())
  2015  					if err != nil {
  2016  						t.Fatalf("error writing row [%v]: %v", i, err)
  2017  					}
  2018  				}
  2019  
  2020  				nrows := tbl.NumRows()
  2021  				if nrows != int64(rslice.Len()) {
  2022  					t.Fatalf("expected num rows [%v]. got [%v] (%v)", rslice.Len(), nrows, table.cols[0].Name)
  2023  				}
  2024  			},
  2025  			// read
  2026  			func() {
  2027  				f, err := Open(fname, ReadOnly)
  2028  				if err != nil {
  2029  					t.Fatalf("error opening file [%v]: %v", fname, err)
  2030  				}
  2031  				defer f.Close()
  2032  
  2033  				hdu := f.HDU(1)
  2034  				tbl := hdu.(*Table)
  2035  				if tbl.Name() != "test" {
  2036  					t.Fatalf("expected table name==%q. got %q", "test", tbl.Name())
  2037  				}
  2038  
  2039  				rslice := reflect.ValueOf(table.table)
  2040  				nrows := tbl.NumRows()
  2041  				if nrows != int64(rslice.Len()) {
  2042  					t.Fatalf("expected num rows [%v]. got [%v]", rslice.Len(), nrows)
  2043  				}
  2044  
  2045  				rows, err := tbl.Read(0, nrows)
  2046  				if err != nil {
  2047  					t.Fatalf("table.Read: %v", err)
  2048  				}
  2049  				count := int64(0)
  2050  				for rows.Next() {
  2051  					ref := rslice.Index(int(count)).Interface().(map[string]interface{})
  2052  					data := map[string]interface{}{}
  2053  					err = rows.Scan(&data)
  2054  					if err != nil {
  2055  						t.Fatalf("rows.Scan: %v", err)
  2056  					}
  2057  					// check data just read in is ok
  2058  					if !reflect.DeepEqual(data, ref) {
  2059  						t.Fatalf("rows.Scan:\nexp=%[1]v (%[1]T)\ngot=%[2]v (%[2]T)", ref, data)
  2060  					}
  2061  					count++
  2062  				}
  2063  				if count != nrows {
  2064  					t.Fatalf("expected [%v] rows. got [%v]", nrows, count)
  2065  				}
  2066  			},
  2067  		} {
  2068  			fct()
  2069  		}
  2070  	}
  2071  }
  2072  
  2073  // EOF