go-hep.org/x/hep@v0.38.1/groot/rarrow/reader_test.go (about)

     1  // Copyright ©2019 The go-hep 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 rarrow // import "go-hep.org/x/hep/groot/rarrow"
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"strings"
    11  	"testing"
    12  
    13  	"git.sr.ht/~sbinet/go-arrow/array"
    14  	"git.sr.ht/~sbinet/go-arrow/memory"
    15  	"go-hep.org/x/hep/groot"
    16  	"go-hep.org/x/hep/groot/riofs"
    17  	"go-hep.org/x/hep/groot/rtree"
    18  )
    19  
    20  func TestRecord(t *testing.T) {
    21  	for _, tc := range []struct {
    22  		file string
    23  		tree string
    24  		want string
    25  	}{
    26  		{
    27  			file: "../testdata/simple.root",
    28  			tree: "tree",
    29  			want: "testdata/simple.root.txt",
    30  		},
    31  		{
    32  			file: "../testdata/small-flat-tree.root",
    33  			tree: "tree",
    34  			want: "testdata/small-flat-tree.root.txt",
    35  		},
    36  		{
    37  			file: "../testdata/small-evnt-tree-fullsplit.root",
    38  			tree: "tree",
    39  			want: "testdata/small-evnt-tree-fullsplit.root.txt",
    40  		},
    41  		{
    42  			file: "../testdata/small-evnt-tree-nosplit.root",
    43  			tree: "tree",
    44  			want: "testdata/small-evnt-tree-nosplit.root.txt",
    45  		},
    46  		{
    47  			// n-dim arrays
    48  			// FIXME(sbinet): arrays of Float16_t and Double32_t are flatten.
    49  			// This is because of:
    50  			// https://sft.its.cern.ch/jira/browse/ROOT-10149
    51  			file: "../testdata/ndim.root",
    52  			tree: "tree",
    53  			want: "testdata/ndim.root.txt",
    54  		},
    55  		{
    56  			// slice of n-dim arrays
    57  			// FIXME(sbinet): arrays of Float16_t and Double32_t are flatten.
    58  			// This is because of:
    59  			// https://sft.its.cern.ch/jira/browse/ROOT-10149
    60  			file: "../testdata/ndim-slice.root",
    61  			tree: "tree",
    62  			want: "testdata/ndim-slice.root.txt",
    63  		},
    64  	} {
    65  		t.Run(tc.file, func(t *testing.T) {
    66  			f, err := groot.Open(tc.file)
    67  			if err != nil {
    68  				t.Fatal(err)
    69  			}
    70  			defer f.Close()
    71  
    72  			o, err := riofs.Dir(f).Get(tc.tree)
    73  			if err != nil {
    74  				t.Fatal(err)
    75  			}
    76  
    77  			mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
    78  			defer mem.AssertSize(t, 0)
    79  
    80  			tree := o.(rtree.Tree)
    81  			rec := NewRecord(tree, WithAllocator(mem))
    82  			defer rec.Release()
    83  
    84  			if got, want := rec.NumCols(), int64(len(tree.Branches())); got != want {
    85  				t.Fatalf("invalid number of columns: got=%d, want=%d", got, want)
    86  			}
    87  
    88  			if got, want := rec.NumRows(), tree.Entries(); got != want {
    89  				t.Fatalf("invalid number of rows: got=%d, want=%d", got, want)
    90  			}
    91  
    92  			for i, branch := range tree.Branches() {
    93  				col := rec.Column(i)
    94  				if got, want := int64(col.Len()), rec.NumRows(); got != want {
    95  					t.Fatalf("invalid column size[%d]: got=%d, want=%d", i, got, want)
    96  				}
    97  				name := rec.ColumnName(i)
    98  				if got, want := name, branch.Name(); got != want {
    99  					t.Fatalf("invalid column name[%d]: got=%q, want=%q", i, got, want)
   100  				}
   101  			}
   102  
   103  			rec.Retain()
   104  			rec.Release()
   105  
   106  			for _, tc := range []struct{ beg, end, want int64 }{
   107  				{0, rec.NumRows(), rec.NumRows()},
   108  				{0, rec.NumRows() - 1, rec.NumRows() - 1},
   109  				{0, 0, 0},
   110  				{0, 1, 1},
   111  				{0, 2, 2},
   112  				{1, 2, 1},
   113  			} {
   114  				t.Run(fmt.Sprintf("slice-%d-%d", tc.beg, tc.end), func(t *testing.T) {
   115  					sub := rec.NewSlice(tc.beg, tc.end)
   116  					defer sub.Release()
   117  
   118  					if got, want := sub.NumCols(), rec.NumCols(); got != want {
   119  						t.Fatalf("invalid number of sub-cols: got=%d, want=%d", got, want)
   120  					}
   121  
   122  					if got, want := sub.NumRows(), tc.want; got != want {
   123  						t.Fatalf("invalid number of sub-rows: got=%d, want=%d", got, want)
   124  					}
   125  				})
   126  			}
   127  
   128  			rr, err := array.NewRecordReader(rec.Schema(), []array.Record{rec})
   129  			if err != nil {
   130  				t.Fatal(err)
   131  			}
   132  			defer rr.Release()
   133  
   134  			recs := 0
   135  			out := new(strings.Builder)
   136  			fmt.Fprintf(out, "file: %s\n", tc.file)
   137  			for rr.Next() {
   138  				rec := rr.Record()
   139  				for i, col := range rec.Columns() {
   140  					fmt.Fprintf(out, "rec[%d][%s]: %v\n", recs, rec.Schema().Field(i).Name, col)
   141  				}
   142  				recs++
   143  			}
   144  
   145  			want, err := os.ReadFile(tc.want)
   146  			if err != nil {
   147  				t.Fatal(err)
   148  			}
   149  
   150  			if got, want := out.String(), string(want); got != want {
   151  				t.Fatalf("invalid table\ngot:\n%s\nwant:\n%s\n", got, want)
   152  			}
   153  		})
   154  	}
   155  }
   156  
   157  func TestRecordReader(t *testing.T) {
   158  	for _, tc := range []struct {
   159  		file  string
   160  		tree  string
   161  		chunk int64
   162  		want  string
   163  	}{
   164  		{
   165  			file:  "../testdata/leaves.root",
   166  			tree:  "tree",
   167  			chunk: -1,
   168  			want:  "testdata/leaves.root.txt",
   169  		},
   170  		{
   171  			file:  "../testdata/simple.root",
   172  			tree:  "tree",
   173  			chunk: -1,
   174  			want:  "testdata/simple.root.txt",
   175  		},
   176  		{
   177  			file:  "../testdata/simple.root",
   178  			tree:  "tree",
   179  			chunk: 0,
   180  			want:  "testdata/simple.root.chunk=1.txt",
   181  		},
   182  		{
   183  			file:  "../testdata/simple.root",
   184  			tree:  "tree",
   185  			chunk: 1,
   186  			want:  "testdata/simple.root.chunk=1.txt",
   187  		},
   188  		{
   189  			file:  "../testdata/simple.root",
   190  			tree:  "tree",
   191  			chunk: 2,
   192  			want:  "testdata/simple.root.chunk=2.txt",
   193  		},
   194  		{
   195  			file:  "../testdata/simple.root",
   196  			tree:  "tree",
   197  			chunk: 3,
   198  			want:  "testdata/simple.root.chunk=3.txt",
   199  		},
   200  		{
   201  			file:  "../testdata/simple.root",
   202  			tree:  "tree",
   203  			chunk: 4,
   204  			want:  "testdata/simple.root.txt",
   205  		},
   206  		{
   207  			file:  "../testdata/small-flat-tree.root",
   208  			tree:  "tree",
   209  			chunk: -1,
   210  			want:  "testdata/small-flat-tree.root.txt",
   211  		},
   212  		{
   213  			file:  "../testdata/small-evnt-tree-fullsplit.root",
   214  			tree:  "tree",
   215  			chunk: -1,
   216  			want:  "testdata/small-evnt-tree-fullsplit.root.txt",
   217  		},
   218  		{
   219  			file:  "../testdata/small-evnt-tree-nosplit.root",
   220  			tree:  "tree",
   221  			chunk: -1,
   222  			want:  "testdata/small-evnt-tree-nosplit.root.txt",
   223  		},
   224  	} {
   225  		t.Run(fmt.Sprintf("%s-with-chunk=%d", tc.file, tc.chunk), func(t *testing.T) {
   226  			f, err := groot.Open(tc.file)
   227  			if err != nil {
   228  				t.Fatal(err)
   229  			}
   230  			defer f.Close()
   231  
   232  			o, err := riofs.Dir(f).Get(tc.tree)
   233  			if err != nil {
   234  				t.Fatal(err)
   235  			}
   236  
   237  			mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
   238  			defer mem.AssertSize(t, 0)
   239  
   240  			tree := o.(rtree.Tree)
   241  			rr := NewRecordReader(tree, WithAllocator(mem), WithChunk(tc.chunk))
   242  			defer rr.Release()
   243  
   244  			rr.Retain()
   245  			rr.Release()
   246  
   247  			recs := 0
   248  			out := new(strings.Builder)
   249  			fmt.Fprintf(out, "file: %s\n", tc.file)
   250  			for rr.Next() {
   251  				rec := rr.Record()
   252  				for i, col := range rec.Columns() {
   253  					fmt.Fprintf(out, "rec[%d][%s]: %v\n", recs, rec.Schema().Field(i).Name, col)
   254  				}
   255  				recs++
   256  			}
   257  
   258  			want, err := os.ReadFile(tc.want)
   259  			if err != nil {
   260  				t.Fatal(err)
   261  			}
   262  
   263  			if got, want := out.String(), string(want); got != want {
   264  				t.Fatalf("invalid table\ngot:\n%s\nwant:\n%s\n", got, want)
   265  			}
   266  		})
   267  	}
   268  }