github.com/SaadMTSA/goreporter@v0.0.0-20200505121753-0437ee0c8f64/linters/copycheck/suffixtree/suffixtree_test.go (about)

     1  package suffixtree
     2  
     3  import "testing"
     4  
     5  type char byte
     6  
     7  func (c char) Val() int {
     8  	return int(c)
     9  }
    10  
    11  func str2tok(str string) []Token {
    12  	toks := make([]Token, len(str))
    13  	for i, c := range str {
    14  		toks[i] = char(c)
    15  	}
    16  	return toks
    17  }
    18  
    19  func TestConstruction(t *testing.T) {
    20  	str := "cacao"
    21  	_, s := genStates(8, str)
    22  	// s[0] is root
    23  	s[0].addTran(0, 1, s[1]) // ca
    24  	s[0].addTran(1, 1, s[2]) // a
    25  	s[0].addTran(4, 4, s[3]) // o
    26  
    27  	s[1].addTran(2, 4, s[4]) // cao
    28  	s[1].addTran(4, 4, s[5]) // o
    29  
    30  	s[2].addTran(2, 4, s[4]) // cao
    31  	s[2].addTran(4, 4, s[5]) // o
    32  
    33  	cacao := New()
    34  	cacao.Update(str2tok(str)...)
    35  	compareTrees(t, s[0], cacao.root)
    36  
    37  	str2 := "banana"
    38  	_, r := genStates(4, str2)
    39  	r[0].addTran(0, 5, r[1]) // banana
    40  	r[0].addTran(1, 5, r[2]) // anana
    41  	r[0].addTran(2, 5, r[3]) // nana
    42  
    43  	banana := New()
    44  	banana.Update(str2tok(str2)...)
    45  	compareTrees(t, r[0], banana.root)
    46  
    47  	_, q := genStates(11, str2+"$")
    48  	// r[0] is root
    49  	q[0].addTran(0, 6, q[1]) // banana$
    50  	q[0].addTran(1, 1, q[2]) // a
    51  	q[0].addTran(2, 3, q[3]) // na
    52  	q[0].addTran(6, 6, q[4]) // $
    53  
    54  	q[2].addTran(2, 3, q[5]) // na
    55  	q[2].addTran(6, 6, q[6]) // $
    56  
    57  	q[3].addTran(4, 6, q[7]) // na$
    58  	q[3].addTran(6, 6, q[8]) // $
    59  
    60  	q[5].addTran(4, 6, q[9])  // na$
    61  	q[5].addTran(6, 6, q[10]) // $
    62  
    63  	banana.Update(char('$'))
    64  	compareTrees(t, q[0], banana.root)
    65  
    66  	foo := New()
    67  	foo.Update(str2tok("a b ac c ")...)
    68  }
    69  
    70  func compareTrees(t *testing.T, expected, actual *state) {
    71  	ch1, ch2 := walker(expected), walker(actual)
    72  	for {
    73  		etran, ok1 := <-ch1
    74  		atran, ok2 := <-ch2
    75  		if !ok1 || !ok2 {
    76  			if ok1 {
    77  				t.Error("expected tree is longer")
    78  			} else if ok2 {
    79  				t.Error("actual tree is longer")
    80  			}
    81  			break
    82  		}
    83  		if etran.start != atran.start || etran.ActEnd() != atran.ActEnd() {
    84  			t.Errorf("got transition (%d, %d) '%s', want (%d, %d) '%s'",
    85  				atran.start, atran.ActEnd(), actual.tree.data[atran.start:atran.ActEnd()+1],
    86  				etran.start, etran.ActEnd(), expected.tree.data[etran.start:etran.ActEnd()+1],
    87  			)
    88  		}
    89  	}
    90  }
    91  
    92  func walker(s *state) <-chan *tran {
    93  	ch := make(chan *tran)
    94  	go func() {
    95  		walk(s, ch)
    96  		close(ch)
    97  	}()
    98  	return ch
    99  }
   100  
   101  func walk(s *state, ch chan<- *tran) {
   102  	for _, tr := range s.trans {
   103  		ch <- tr
   104  		walk(tr.state, ch)
   105  	}
   106  }
   107  
   108  func genStates(count int, data string) (*STree, []*state) {
   109  	t := new(STree)
   110  	t.data = str2tok(data)
   111  	states := make([]*state, count)
   112  	for i := range states {
   113  		states[i] = newState(t)
   114  	}
   115  	return t, states
   116  }
   117  
   118  type refPair struct {
   119  	s          *state
   120  	start, end Pos
   121  }
   122  
   123  func TestCanonize(t *testing.T) {
   124  	tree, s := genStates(5, "somebanana")
   125  	tree.auxState, tree.root = s[4], s[0]
   126  	s[0].addTran(0, 3, s[1])
   127  	s[1].addTran(4, 6, s[2])
   128  	s[2].addTran(7, infinity, s[3])
   129  
   130  	find := func(needle *state) int {
   131  		for i, state := range s {
   132  			if state == needle {
   133  				return i
   134  			}
   135  		}
   136  		return -1
   137  	}
   138  
   139  	var testCases = []struct {
   140  		origin, expected refPair
   141  	}{
   142  		{refPair{s[0], 0, 0}, refPair{s[0], 0, 0}},
   143  		{refPair{s[0], 0, 2}, refPair{s[0], 0, 0}},
   144  		{refPair{s[0], 0, 3}, refPair{s[1], 4, 0}},
   145  		{refPair{s[0], 0, 8}, refPair{s[2], 7, 0}},
   146  		{refPair{s[0], 0, 6}, refPair{s[2], 7, 0}},
   147  		{refPair{s[0], 0, 100}, refPair{s[2], 7, 0}},
   148  		{refPair{s[4], -1, 100}, refPair{s[2], 7, 0}},
   149  	}
   150  
   151  	for _, tc := range testCases {
   152  		s, start := tree.canonize(tc.origin.s, tc.origin.start, tc.origin.end)
   153  		if s != tc.expected.s || start != tc.expected.start {
   154  			t.Errorf("for origin ref. pair (%d, (%d, %d)) got (%d, %d), want (%d, %d)",
   155  				find(tc.origin.s), tc.origin.start, tc.origin.end,
   156  				find(s), start,
   157  				find(tc.expected.s), tc.expected.start,
   158  			)
   159  		}
   160  	}
   161  }
   162  
   163  func TestSplitting(t *testing.T) {
   164  	tree := new(STree)
   165  	tree.data = str2tok("banana|cbao")
   166  	s1 := newState(tree)
   167  	s2 := newState(tree)
   168  	s1.addTran(0, 3, s2)
   169  
   170  	// active point is (s1, 0, -1), an explicit state
   171  	tree.end = 7 // c
   172  	rets, end := tree.testAndSplit(s1, 0, -1)
   173  	if rets != s1 {
   174  		t.Errorf("got state %p, want %p", rets, s1)
   175  	}
   176  	if end {
   177  		t.Error("should not be an end-point")
   178  	}
   179  	tree.end = 8 // b
   180  	_, end = tree.testAndSplit(s1, 0, -1)
   181  	if !end {
   182  		t.Error("should be an end-point")
   183  	}
   184  
   185  	// active point is (s1, 0, 2), an implicit state
   186  	tree.end = 9 // a
   187  	rets, end = tree.testAndSplit(s1, 0, 2)
   188  	if rets != s1 {
   189  		t.Error("returned state should be unchanged")
   190  	}
   191  	if !end {
   192  		t.Error("should be an end-point")
   193  	}
   194  
   195  	// [s1]-banana->[s2] => [s1]-ban->[rets]-ana->[s2]
   196  	tree.end = 10 // o
   197  	rets, end = tree.testAndSplit(s1, 0, 2)
   198  	tr := s1.findTran(char('b'))
   199  	if tr == nil {
   200  		t.Error("should have a b-transition")
   201  	} else if tr.state != rets {
   202  		t.Errorf("got state %p, want %p", tr.state, rets)
   203  	}
   204  	tr2 := rets.findTran(char('a'))
   205  	if tr2 == nil {
   206  		t.Error("should have an a-transition")
   207  	} else if tr2.state != s2 {
   208  		t.Errorf("got state %p, want %p", tr2.state, s2)
   209  	}
   210  	if end {
   211  		t.Error("should not be an end-point")
   212  	}
   213  }
   214  
   215  func TestPosMaxValue(t *testing.T) {
   216  	var p Pos = infinity
   217  	if p+1 > 0 {
   218  		t.Error("const infinity is not max value")
   219  	}
   220  }
   221  
   222  func BenchmarkConstruction(b *testing.B) {
   223  	stream := str2tok(`all work and no play makes jack a dull boy
   224  all work and no play makes jack a dull boy
   225  all work and no play makes jack a dull boy`)
   226  
   227  	for i := 0; i < b.N; i++ {
   228  		t := New()
   229  		t.Update(stream...)
   230  	}
   231  }