go-hep.org/x/hep@v0.38.1/groot/rtree/join_test.go (about)

     1  // Copyright ©2020 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 rtree
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"testing"
    11  
    12  	"go-hep.org/x/hep/groot/riofs"
    13  )
    14  
    15  func TestJoin(t *testing.T) {
    16  	loadTree := func(fname, tname string) (Tree, func() error) {
    17  		f, err := riofs.Open(fname)
    18  		if err != nil {
    19  			t.Fatalf("could not open %q: %+v", fname, err)
    20  		}
    21  		o, err := riofs.Dir(f).Get(tname)
    22  		if err != nil {
    23  			t.Fatalf("could not get tree %q from %q: %+v", tname, fname, err)
    24  		}
    25  
    26  		return o.(Tree), f.Close
    27  	}
    28  	chk := func(f func() error) {
    29  		err := f()
    30  		if err != nil {
    31  			t.Fatal(err)
    32  		}
    33  	}
    34  
    35  	j1, close1 := loadTree("../testdata/join1.root", "j1")
    36  	defer chk(close1)
    37  
    38  	j2, close2 := loadTree("../testdata/join2.root", "j2")
    39  	defer chk(close2)
    40  
    41  	j3, close3 := loadTree("../testdata/join3.root", "j3")
    42  	defer chk(close3)
    43  
    44  	j41, close41 := loadTree("../testdata/join4.root", "j41")
    45  	defer chk(close41)
    46  
    47  	j42, close42 := loadTree("../testdata/join4.root", "j42")
    48  	defer chk(close42)
    49  
    50  	for _, tc := range []struct {
    51  		test  string
    52  		trees []Tree
    53  		name  string
    54  		title string
    55  		nevts int64
    56  		rvars []ReadVar
    57  		brs   []string
    58  		brOK  string
    59  		brNOT string
    60  		lvs   []string
    61  		lvOK  string
    62  		lvNOT string
    63  		err   error
    64  	}{
    65  		{
    66  			test:  "empty",
    67  			trees: nil,
    68  			err:   fmt.Errorf("rtree: no trees to join"),
    69  		},
    70  		{
    71  			test:  "entries-differ-j1-j41",
    72  			trees: []Tree{j1, j41},
    73  			err:   fmt.Errorf("rtree: invalid number of entries in tree j41 (got=11, want=10)"),
    74  		},
    75  		{
    76  			test:  "entries-differ-j41-j1",
    77  			trees: []Tree{j41, j1},
    78  			err:   fmt.Errorf("rtree: invalid number of entries in tree j1 (got=10, want=11)"),
    79  		},
    80  		{
    81  			test:  "branch-collision-1-same-type",
    82  			trees: []Tree{j2, j42},
    83  			err:   fmt.Errorf("rtree: trees j2 and j42 both have a branch named b22"),
    84  		},
    85  		{
    86  			test:  "branch-collision-2-same-type",
    87  			trees: []Tree{j42, j2},
    88  			err:   fmt.Errorf("rtree: trees j42 and j2 both have a branch named b22"),
    89  		},
    90  		{
    91  			test:  "branch-collision-1-diff-type",
    92  			trees: []Tree{j1, j42},
    93  			err:   fmt.Errorf("rtree: trees j1 and j42 both have a branch named b11"),
    94  		},
    95  		{
    96  			test:  "branch-collision-2-diff-type",
    97  			trees: []Tree{j42, j1},
    98  			err:   fmt.Errorf("rtree: trees j42 and j1 both have a branch named b11"),
    99  		},
   100  		{
   101  			test:  "join-j1",
   102  			trees: []Tree{j1},
   103  			nevts: 10,
   104  			name:  "join_j1",
   105  			title: "j1-tree",
   106  			rvars: []ReadVar{
   107  				{Name: "b10", Leaf: "b10", Value: new(float64)},
   108  				{Name: "b11", Leaf: "b11", Value: new(int64)},
   109  				{Name: "b12", Leaf: "b12", Value: new(string)},
   110  			},
   111  			brs: []string{
   112  				"b10", "b11", "b12",
   113  			},
   114  			brOK:  "b10",
   115  			brNOT: "b40",
   116  			lvs: []string{
   117  				"b10", "b11", "b12",
   118  			},
   119  			lvOK:  "b10",
   120  			lvNOT: "b40",
   121  		},
   122  		{
   123  			test:  "join-j2",
   124  			trees: []Tree{j2},
   125  			nevts: 10,
   126  			name:  "join_j2",
   127  			title: "j2-tree",
   128  			rvars: []ReadVar{
   129  				{Name: "b20", Leaf: "b20", Value: new(float64)},
   130  				{Name: "b21", Leaf: "b21", Value: new(int64)},
   131  				{Name: "b22", Leaf: "b22", Value: new(string)},
   132  			},
   133  			brs: []string{
   134  				"b20", "b21", "b22",
   135  			},
   136  			brOK:  "b20",
   137  			brNOT: "b40",
   138  			lvs: []string{
   139  				"b20", "b21", "b22",
   140  			},
   141  			lvOK:  "b20",
   142  			lvNOT: "b40",
   143  		},
   144  		{
   145  			test:  "join-j3",
   146  			trees: []Tree{j3},
   147  			nevts: 10,
   148  			name:  "join_j3",
   149  			title: "j3-tree",
   150  			rvars: []ReadVar{
   151  				{Name: "b30", Leaf: "b30", Value: new(float64)},
   152  				{Name: "b31", Leaf: "b31", Value: new(int64)},
   153  				{Name: "b32", Leaf: "b32", Value: new(string)},
   154  			},
   155  			brs: []string{
   156  				"b30", "b31", "b32",
   157  			},
   158  			brOK:  "b30",
   159  			brNOT: "b40",
   160  			lvs: []string{
   161  				"b30", "b31", "b32",
   162  			},
   163  			lvOK:  "b30",
   164  			lvNOT: "b40",
   165  		},
   166  		{
   167  			test:  "join-j1-j2-j3",
   168  			trees: []Tree{j1, j2, j3},
   169  			nevts: 10,
   170  			name:  "join_j1_j2_j3",
   171  			title: "j1-tree, j2-tree, j3-tree",
   172  			rvars: []ReadVar{
   173  				{Name: "b10", Leaf: "b10", Value: new(float64)},
   174  				{Name: "b11", Leaf: "b11", Value: new(int64)},
   175  				{Name: "b12", Leaf: "b12", Value: new(string)},
   176  				{Name: "b20", Leaf: "b20", Value: new(float64)},
   177  				{Name: "b21", Leaf: "b21", Value: new(int64)},
   178  				{Name: "b22", Leaf: "b22", Value: new(string)},
   179  				{Name: "b30", Leaf: "b30", Value: new(float64)},
   180  				{Name: "b31", Leaf: "b31", Value: new(int64)},
   181  				{Name: "b32", Leaf: "b32", Value: new(string)},
   182  			},
   183  			brs: []string{
   184  				"b10", "b11", "b12",
   185  				"b20", "b21", "b22",
   186  				"b30", "b31", "b32",
   187  			},
   188  			brOK:  "b10",
   189  			brNOT: "b40",
   190  			lvs: []string{
   191  				"b10", "b11", "b12",
   192  				"b20", "b21", "b22",
   193  				"b30", "b31", "b32",
   194  			},
   195  			lvOK:  "b10",
   196  			lvNOT: "b40",
   197  		},
   198  		{
   199  			test:  "join-j1-j2",
   200  			trees: []Tree{j1, j2},
   201  			nevts: 10,
   202  			name:  "join_j1_j2",
   203  			title: "j1-tree, j2-tree",
   204  			rvars: []ReadVar{
   205  				{Name: "b10", Leaf: "b10", Value: new(float64)},
   206  				{Name: "b11", Leaf: "b11", Value: new(int64)},
   207  				{Name: "b12", Leaf: "b12", Value: new(string)},
   208  				{Name: "b20", Leaf: "b20", Value: new(float64)},
   209  				{Name: "b21", Leaf: "b21", Value: new(int64)},
   210  				{Name: "b22", Leaf: "b22", Value: new(string)},
   211  			},
   212  			brs: []string{
   213  				"b10", "b11", "b12",
   214  				"b20", "b21", "b22",
   215  			},
   216  			brOK:  "b10",
   217  			brNOT: "b30",
   218  			lvs: []string{
   219  				"b10", "b11", "b12",
   220  				"b20", "b21", "b22",
   221  			},
   222  			lvOK:  "b10",
   223  			lvNOT: "b30",
   224  		},
   225  		{
   226  			test:  "join-j2-j1",
   227  			trees: []Tree{j2, j1},
   228  			nevts: 10,
   229  			name:  "join_j2_j1",
   230  			title: "j2-tree, j1-tree",
   231  			rvars: []ReadVar{
   232  				{Name: "b20", Leaf: "b20", Value: new(float64)},
   233  				{Name: "b21", Leaf: "b21", Value: new(int64)},
   234  				{Name: "b22", Leaf: "b22", Value: new(string)},
   235  				{Name: "b10", Leaf: "b10", Value: new(float64)},
   236  				{Name: "b11", Leaf: "b11", Value: new(int64)},
   237  				{Name: "b12", Leaf: "b12", Value: new(string)},
   238  			},
   239  			brs: []string{
   240  				"b20", "b21", "b22",
   241  				"b10", "b11", "b12",
   242  			},
   243  			brOK:  "b10",
   244  			brNOT: "b30",
   245  			lvs: []string{
   246  				"b20", "b21", "b22",
   247  				"b10", "b11", "b12",
   248  			},
   249  			lvOK:  "b10",
   250  			lvNOT: "b30",
   251  		},
   252  		{
   253  			test:  "join-j1-j3",
   254  			trees: []Tree{j1, j3},
   255  			nevts: 10,
   256  			name:  "join_j1_j3",
   257  			title: "j1-tree, j3-tree",
   258  			rvars: []ReadVar{
   259  				{Name: "b10", Leaf: "b10", Value: new(float64)},
   260  				{Name: "b11", Leaf: "b11", Value: new(int64)},
   261  				{Name: "b12", Leaf: "b12", Value: new(string)},
   262  				{Name: "b30", Leaf: "b30", Value: new(float64)},
   263  				{Name: "b31", Leaf: "b31", Value: new(int64)},
   264  				{Name: "b32", Leaf: "b32", Value: new(string)},
   265  			},
   266  			brs: []string{
   267  				"b10", "b11", "b12",
   268  				"b30", "b31", "b32",
   269  			},
   270  			brOK:  "b10",
   271  			brNOT: "b40",
   272  			lvs: []string{
   273  				"b10", "b11", "b12",
   274  				"b30", "b31", "b32",
   275  			},
   276  			lvOK:  "b10",
   277  			lvNOT: "b40",
   278  		},
   279  		{
   280  			test:  "join-j2-j3",
   281  			trees: []Tree{j2, j3},
   282  			nevts: 10,
   283  			name:  "join_j2_j3",
   284  			title: "j2-tree, j3-tree",
   285  			rvars: []ReadVar{
   286  				{Name: "b20", Leaf: "b20", Value: new(float64)},
   287  				{Name: "b21", Leaf: "b21", Value: new(int64)},
   288  				{Name: "b22", Leaf: "b22", Value: new(string)},
   289  				{Name: "b30", Leaf: "b30", Value: new(float64)},
   290  				{Name: "b31", Leaf: "b31", Value: new(int64)},
   291  				{Name: "b32", Leaf: "b32", Value: new(string)},
   292  			},
   293  			brs: []string{
   294  				"b20", "b21", "b22",
   295  				"b30", "b31", "b32",
   296  			},
   297  			brOK:  "b20",
   298  			brNOT: "b10",
   299  			lvs: []string{
   300  				"b20", "b21", "b22",
   301  				"b30", "b31", "b32",
   302  			},
   303  			lvOK:  "b20",
   304  			lvNOT: "b10",
   305  		},
   306  	} {
   307  		t.Run(tc.test, func(t *testing.T) {
   308  			tree, err := Join(tc.trees...)
   309  			switch {
   310  			case err != nil && tc.err != nil:
   311  				if got, want := err.Error(), tc.err.Error(); got != want {
   312  					t.Fatalf("invalid error:\ngot= %s\nwant=%s", got, want)
   313  				}
   314  				return
   315  			case err != nil && tc.err == nil:
   316  				t.Fatalf("could not join trees: %+v", err)
   317  			case err == nil && tc.err != nil:
   318  				t.Fatalf("invalid error:\ngot= %v\nwant: %s", err, tc.err.Error())
   319  			case err == nil && tc.err == nil:
   320  				// ok.
   321  			}
   322  
   323  			if got, want := tree.Class(), "TJoin"; got != want {
   324  				t.Fatalf("invalid class:\ngot= %q\nwant=%q", got, want)
   325  			}
   326  
   327  			if got, want := tree.Name(), tc.name; got != want {
   328  				t.Fatalf("invalid name:\ngot= %q\nwant=%q", got, want)
   329  			}
   330  
   331  			if got, want := tree.Title(), tc.title; got != want {
   332  				t.Fatalf("invalid title:\ngot= %q\nwant=%q", got, want)
   333  			}
   334  
   335  			if got, want := tree.Entries(), tc.nevts; got != want {
   336  				t.Fatalf("invalid entries: got=%d, want=%d", got, want)
   337  			}
   338  			{
   339  				rvars := NewReadVars(tree)
   340  				n := min(len(rvars), len(tc.rvars))
   341  
   342  				for i := range n {
   343  					got := rvars[i]
   344  					want := tc.rvars[i]
   345  					if got.Name != want.Name {
   346  						t.Fatalf("invalid rvar-name[%d]: got=%q, want=%q", i, got.Name, want.Name)
   347  					}
   348  					if got.Leaf != want.Leaf {
   349  						t.Fatalf("invalid rvar-leaf[%d]: got=%q, want=%q", i, got.Leaf, want.Leaf)
   350  					}
   351  					if got, want := reflect.TypeOf(got.Value), reflect.TypeOf(want.Value); got != want {
   352  						t.Fatalf("invalid rvar (name=%q) type[%d]: got=%v, want=%v", rvars[i].Name, i, got, want)
   353  					}
   354  				}
   355  
   356  				if got, want := len(rvars), len(tc.rvars); got != want {
   357  					t.Fatalf("invalid number of rvars: got=%d, want=%d", got, want)
   358  				}
   359  			}
   360  			{
   361  				brs := tree.Branches()
   362  				n := min(len(brs), len(tc.brs))
   363  
   364  				for i := range n {
   365  					if got, want := brs[i].Name(), tc.brs[i]; got != want {
   366  						t.Fatalf("invalid branch name[%d]: got=%q, want=%q", i, got, want)
   367  					}
   368  				}
   369  
   370  				if got, want := len(brs), len(tc.brs); got != want {
   371  					t.Fatalf("invalid number of branches: got=%d, want=%d", got, want)
   372  				}
   373  
   374  				br := tree.Branch(tc.brOK)
   375  				if br == nil {
   376  					t.Fatalf("could not retrieve branch %q", tc.brOK)
   377  				}
   378  				if got, want := br.Name(), tc.brOK; got != want {
   379  					t.Fatalf("invalid name for branch-ok: got=%q, want=%q", got, want)
   380  				}
   381  
   382  				br = tree.Branch(tc.brNOT)
   383  				if br != nil {
   384  					t.Fatalf("unexpected branch for branch-not (%s): got=%#v", tc.brNOT, br)
   385  				}
   386  			}
   387  			{
   388  				lvs := tree.Leaves()
   389  				n := min(len(lvs), len(tc.lvs))
   390  
   391  				for i := range n {
   392  					if got, want := lvs[i].Name(), tc.lvs[i]; got != want {
   393  						t.Fatalf("invalid leaf name[%d]: got=%q, want=%q", i, got, want)
   394  					}
   395  				}
   396  
   397  				if got, want := len(lvs), len(tc.lvs); got != want {
   398  					t.Fatalf("invalid number of leaves: got=%d, want=%d", got, want)
   399  				}
   400  
   401  				lv := tree.Leaf(tc.lvOK)
   402  				if lv == nil {
   403  					t.Fatalf("could not retrieve leaf %q", tc.lvOK)
   404  				}
   405  				if got, want := lv.Name(), tc.lvOK; got != want {
   406  					t.Fatalf("invalid name for leaf-ok: got=%q, want=%q", got, want)
   407  				}
   408  				br := lv.Branch()
   409  				if br == nil || br.Name() != tc.lvOK {
   410  					t.Fatalf("invalid leaf-branch: ptr-ok=%v", br != nil)
   411  				}
   412  
   413  				lv = tree.Leaf(tc.lvNOT)
   414  				if lv != nil {
   415  					t.Fatalf("unexpected leaf for leaf-not (%s): got=%#v", tc.lvNOT, lv)
   416  				}
   417  			}
   418  		})
   419  	}
   420  }