github.com/CiscoM31/godata@v1.0.10/parser_test.go (about)

     1  package godata
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  	"testing"
     7  )
     8  
     9  func TestPEMDAS(t *testing.T) {
    10  	ctx := context.Background()
    11  	parser := EmptyParser()
    12  	parser.DefineFunction("sin", []int{1}, false)
    13  	parser.DefineFunction("max", []int{2}, false)
    14  	parser.DefineOperator("^", 2, OpAssociationRight, 5)
    15  	parser.DefineOperator("*", 2, OpAssociationLeft, 5)
    16  	parser.DefineOperator("/", 2, OpAssociationLeft, 5)
    17  	parser.DefineOperator("+", 2, OpAssociationLeft, 4)
    18  	parser.DefineOperator("-", 2, OpAssociationLeft, 4)
    19  
    20  	// 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3
    21  	tokens := []*Token{
    22  		{Value: "3"},
    23  		{Value: "+"},
    24  		{Value: "4"},
    25  		{Value: "*"},
    26  		{Value: "2"},
    27  		{Value: "/"},
    28  		{Value: "("},
    29  		{Value: "1"},
    30  		{Value: "-"},
    31  		{Value: "5"},
    32  		{Value: ")"},
    33  		{Value: "^"},
    34  		{Value: "2"},
    35  		{Value: "^"},
    36  		{Value: "3"},
    37  	}
    38  
    39  	// 3 4 2 * 1 5 - 2 3 ^ ^ / +
    40  	expected := []string{"3", "4", "2", "*", "1", "5", "-", "2", "3", "^", "^",
    41  		"/", "+"}
    42  
    43  	result, err := parser.InfixToPostfix(ctx, tokens)
    44  
    45  	if err != nil {
    46  		t.Error(err)
    47  		return
    48  	}
    49  
    50  	for i, v := range expected {
    51  		if result.Empty() {
    52  			t.Error("Output is not the expected length.")
    53  			return
    54  		}
    55  
    56  		token := result.Dequeue()
    57  		if v != token.Value {
    58  			t.Error("Expected " + v + " at index " + strconv.Itoa(i) + " got " +
    59  				token.Value)
    60  		}
    61  	}
    62  }
    63  
    64  func BenchmarkPEMDAS(b *testing.B) {
    65  	ctx := context.Background()
    66  	parser := EmptyParser()
    67  	parser.DefineFunction("sin", []int{1}, false)
    68  	parser.DefineFunction("max", []int{2}, false)
    69  	parser.DefineOperator("^", 2, OpAssociationRight, 5)
    70  	parser.DefineOperator("*", 2, OpAssociationLeft, 5)
    71  	parser.DefineOperator("/", 2, OpAssociationLeft, 5)
    72  	parser.DefineOperator("+", 2, OpAssociationLeft, 4)
    73  	parser.DefineOperator("-", 2, OpAssociationLeft, 4)
    74  
    75  	// 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3
    76  	tokens := []*Token{
    77  		{Value: "3"},
    78  		{Value: "+"},
    79  		{Value: "4"},
    80  		{Value: "*"},
    81  		{Value: "2"},
    82  		{Value: "/"},
    83  		{Value: "("},
    84  		{Value: "1"},
    85  		{Value: "-"},
    86  		{Value: "5"},
    87  		{Value: ")"},
    88  		{Value: "^"},
    89  		{Value: "2"},
    90  		{Value: "^"},
    91  		{Value: "3"},
    92  	}
    93  
    94  	for i := 0; i < b.N; i++ {
    95  		if _, err := parser.InfixToPostfix(ctx, tokens); err != nil {
    96  			b.Fatalf("Failed to transform tokens from infix to postfix: %v", err)
    97  		}
    98  	}
    99  }
   100  
   101  func TestBoolean(t *testing.T) {
   102  	ctx := context.Background()
   103  	parser := EmptyParser()
   104  	parser.DefineOperator("NOT", 1, OpAssociationNone, 3)
   105  	parser.DefineOperator("AND", 2, OpAssociationLeft, 2)
   106  	parser.DefineOperator("OR", 2, OpAssociationLeft, 1)
   107  
   108  	// (A OR NOT B) AND C OR B
   109  	tokens := []*Token{
   110  		{Value: "("},
   111  		{Value: "A"},
   112  		{Value: "OR"},
   113  		{Value: "NOT"},
   114  		{Value: "B"},
   115  		{Value: ")"},
   116  		{Value: "AND"},
   117  		{Value: "C"},
   118  		{Value: "OR"},
   119  		{Value: "B"},
   120  	}
   121  
   122  	// A B NOT OR C AND B OR
   123  	expected := []string{"A", "B", "NOT", "OR", "C", "AND", "B", "OR"}
   124  	result, err := parser.InfixToPostfix(ctx, tokens)
   125  
   126  	if err != nil {
   127  		t.Error(err)
   128  		return
   129  	}
   130  
   131  	for i, v := range expected {
   132  		if result.Empty() {
   133  			t.Error("Output is not the expected length.")
   134  			return
   135  		}
   136  
   137  		token := result.Dequeue()
   138  		if v != token.Value {
   139  			t.Error("Expected " + v + " at index " + strconv.Itoa(i) + " got " +
   140  				token.Value)
   141  		}
   142  	}
   143  }
   144  
   145  func TestFunc(t *testing.T) {
   146  	ctx := context.Background()
   147  	parser := EmptyParser()
   148  	parser.DefineFunction("sin", []int{1}, false)
   149  	parser.DefineFunction("max", []int{2}, false)
   150  	parser.DefineFunction("volume", []int{3}, false)
   151  	parser.DefineOperator("^", 2, OpAssociationRight, 5)
   152  	parser.DefineOperator("*", 2, OpAssociationLeft, 5)
   153  	parser.DefineOperator("/", 2, OpAssociationLeft, 5)
   154  	parser.DefineOperator("+", 2, OpAssociationLeft, 4)
   155  	parser.DefineOperator("-", 2, OpAssociationLeft, 4)
   156  
   157  	// max(sin(5*pi)+3, sin(5)+volume(3,2,4)/[]int{3})
   158  	tokens := []*Token{
   159  		{Value: "max"},
   160  		{Value: "("},
   161  		{Value: "sin"},
   162  		{Value: "("},
   163  		{Value: "5"},
   164  		{Value: "*"},
   165  		{Value: "pi"},
   166  		{Value: ")"},
   167  		{Value: "+"},
   168  		{Value: "3"},
   169  		{Value: ","},
   170  		{Value: "sin"},
   171  		{Value: "("},
   172  		{Value: "5"},
   173  		{Value: ")"},
   174  		{Value: "+"},
   175  		{Value: "volume"},
   176  		{Value: "("},
   177  		{Value: "3"},
   178  		{Value: ","},
   179  		{Value: "2"},
   180  		{Value: ","},
   181  		{Value: "4"},
   182  		{Value: ")"},
   183  		{Value: "/"},
   184  		{Value: "2"},
   185  		{Value: ")"},
   186  	}
   187  
   188  	// 5 pi * sin 3 + 5 sin 3 2 4 volume 2 / + max
   189  	expected := []string{
   190  		"5", "pi", "*", "1" /* arg count */, "list", /* list expression */
   191  		"sin", "3", "+", "5", "1" /* arg count */, "list", /* list expression */
   192  		"sin", "3", "2", "4", "3" /* arg count */, "list", /* list expression */
   193  		"volume", "2",
   194  		"/", "+",
   195  		"2" /* arg count */, "list" /* list expression */, "max"}
   196  	result, err := parser.InfixToPostfix(ctx, tokens)
   197  
   198  	if err != nil {
   199  		t.Error(err)
   200  		return
   201  	}
   202  
   203  	for i, v := range expected {
   204  		if result.Empty() {
   205  			t.Error("Output is not the expected length.")
   206  			return
   207  		}
   208  
   209  		token := result.Dequeue()
   210  		if v != token.Value {
   211  			t.Errorf("Expected %v at index %d got %v", v, i, token.Value)
   212  		}
   213  	}
   214  }
   215  
   216  func TestTree(t *testing.T) {
   217  	ctx := context.Background()
   218  	parser := EmptyParser()
   219  	parser.DefineFunction("sin", []int{1}, false)
   220  	parser.DefineFunction("max", []int{2}, false)
   221  	parser.DefineOperator("^", 2, OpAssociationRight, 5)
   222  	parser.DefineOperator("*", 2, OpAssociationLeft, 5)
   223  	parser.DefineOperator("/", 2, OpAssociationLeft, 5)
   224  	parser.DefineOperator("+", 2, OpAssociationLeft, 4)
   225  	parser.DefineOperator("-", 2, OpAssociationLeft, 4)
   226  
   227  	// sin ( max ( 2, 3 ) / 3 * 3.1415 )
   228  	tokens := []*Token{
   229  		{Value: "sin"},
   230  		{Value: "("},
   231  		{Value: "max"},
   232  		{Value: "("},
   233  		{Value: "2"},
   234  		{Value: ","},
   235  		{Value: "3"},
   236  		{Value: ")"},
   237  		{Value: "/"},
   238  		{Value: "3"},
   239  		{Value: "*"},
   240  		{Value: "pi"},
   241  		{Value: ")"},
   242  	}
   243  
   244  	// 2 3 max 3 / 3.1415 * sin
   245  	result, err := parser.InfixToPostfix(ctx, tokens)
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  
   250  	root, err := parser.PostfixToTree(ctx, result)
   251  	if err != nil {
   252  		t.Fatalf("Error parsing query: %v", err)
   253  	}
   254  	if root.Token.Value != "sin" {
   255  		t.Error("Root node is not sin")
   256  	}
   257  	if root.Children[0].Token.Value != "*" {
   258  		t.Error("Level 2 node is not *")
   259  	}
   260  	if root.Children[0].Children[1].Token.Value != "pi" {
   261  		t.Error("Level 3 right node is not pi", root.Children[0].Children[1].Token.Value)
   262  	}
   263  	if root.Children[0].Children[0].Token.Value != "/" {
   264  		t.Error("Level 3 left node is not /", root.Children[0].Children[0].Token.Value)
   265  	}
   266  	if root.Children[0].Children[0].Children[1].Token.Value != "3" {
   267  		t.Error("Level 4 right node is not 3", root.Children[0].Children[0].Children[1].Token.Value)
   268  	}
   269  	if root.Children[0].Children[0].Children[0].Token.Value != "max" {
   270  		t.Error("Level 4 left node is not max", root.Children[0].Children[0].Children[0].Token.Value)
   271  	}
   272  	if root.Children[0].Children[0].Children[0].Children[0].Token.Value != "2" {
   273  		t.Error("Level 5 ieft node is not 2", root.Children[0].Children[0].Children[0].Children[0].Token.Value)
   274  	}
   275  	if root.Children[0].Children[0].Children[0].Children[1].Token.Value != "3" {
   276  		t.Error("Level 5 right node is not 3", root.Children[0].Children[0].Children[0].Children[1].Token.Value)
   277  	}
   278  }
   279  
   280  func BenchmarkBuildTree(b *testing.B) {
   281  	ctx := context.Background()
   282  	parser := EmptyParser()
   283  	parser.DefineFunction("sin", []int{1}, false)
   284  	parser.DefineFunction("max", []int{2}, false)
   285  	parser.DefineOperator("^", 2, OpAssociationRight, 5)
   286  	parser.DefineOperator("*", 2, OpAssociationLeft, 5)
   287  	parser.DefineOperator("/", 2, OpAssociationLeft, 5)
   288  	parser.DefineOperator("+", 2, OpAssociationLeft, 4)
   289  	parser.DefineOperator("-", 2, OpAssociationLeft, 4)
   290  
   291  	// sin ( max ( 2, 3 ) / 3 * 3.1415 )
   292  	tokens := []*Token{
   293  		{Value: "sin"},
   294  		{Value: "("},
   295  		{Value: "max"},
   296  		{Value: "("},
   297  		{Value: "2"},
   298  		{Value: ","},
   299  		{Value: "3"},
   300  		{Value: ")"},
   301  		{Value: "/"},
   302  		{Value: "3"},
   303  		{Value: "*"},
   304  		{Value: "pi"},
   305  		{Value: ")"},
   306  	}
   307  
   308  	// 2 3 max 3 / 3.1415 * sin
   309  	for i := 0; i < b.N; i++ {
   310  		result, _ := parser.InfixToPostfix(ctx, tokens)
   311  		if _, err := parser.PostfixToTree(ctx, result); err != nil {
   312  			b.Fatalf("Failed to transform tokens: %v", err)
   313  		}
   314  	}
   315  }