github.com/opentofu/opentofu@v1.7.1/internal/lang/funcs/number_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package funcs
     7  
     8  import (
     9  	"fmt"
    10  	"testing"
    11  
    12  	"github.com/opentofu/opentofu/internal/lang/marks"
    13  	"github.com/zclconf/go-cty/cty"
    14  )
    15  
    16  func TestLog(t *testing.T) {
    17  	tests := []struct {
    18  		Num  cty.Value
    19  		Base cty.Value
    20  		Want cty.Value
    21  		Err  bool
    22  	}{
    23  		{
    24  			cty.NumberFloatVal(1),
    25  			cty.NumberFloatVal(10),
    26  			cty.NumberFloatVal(0),
    27  			false,
    28  		},
    29  		{
    30  			cty.NumberFloatVal(10),
    31  			cty.NumberFloatVal(10),
    32  			cty.NumberFloatVal(1),
    33  			false,
    34  		},
    35  
    36  		{
    37  			cty.NumberFloatVal(0),
    38  			cty.NumberFloatVal(10),
    39  			cty.NegativeInfinity,
    40  			false,
    41  		},
    42  		{
    43  			cty.NumberFloatVal(10),
    44  			cty.NumberFloatVal(0),
    45  			cty.NumberFloatVal(-0),
    46  			false,
    47  		},
    48  	}
    49  
    50  	for _, test := range tests {
    51  		t.Run(fmt.Sprintf("log(%#v, %#v)", test.Num, test.Base), func(t *testing.T) {
    52  			got, err := Log(test.Num, test.Base)
    53  
    54  			if test.Err {
    55  				if err == nil {
    56  					t.Fatal("succeeded; want error")
    57  				}
    58  				return
    59  			} else if err != nil {
    60  				t.Fatalf("unexpected error: %s", err)
    61  			}
    62  
    63  			if !got.RawEquals(test.Want) {
    64  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
    65  			}
    66  		})
    67  	}
    68  }
    69  
    70  func TestPow(t *testing.T) {
    71  	tests := []struct {
    72  		Num   cty.Value
    73  		Power cty.Value
    74  		Want  cty.Value
    75  		Err   bool
    76  	}{
    77  		{
    78  			cty.NumberFloatVal(1),
    79  			cty.NumberFloatVal(0),
    80  			cty.NumberFloatVal(1),
    81  			false,
    82  		},
    83  		{
    84  			cty.NumberFloatVal(1),
    85  			cty.NumberFloatVal(1),
    86  			cty.NumberFloatVal(1),
    87  			false,
    88  		},
    89  
    90  		{
    91  			cty.NumberFloatVal(2),
    92  			cty.NumberFloatVal(0),
    93  			cty.NumberFloatVal(1),
    94  			false,
    95  		},
    96  		{
    97  			cty.NumberFloatVal(2),
    98  			cty.NumberFloatVal(1),
    99  			cty.NumberFloatVal(2),
   100  			false,
   101  		},
   102  		{
   103  			cty.NumberFloatVal(3),
   104  			cty.NumberFloatVal(2),
   105  			cty.NumberFloatVal(9),
   106  			false,
   107  		},
   108  		{
   109  			cty.NumberFloatVal(-3),
   110  			cty.NumberFloatVal(2),
   111  			cty.NumberFloatVal(9),
   112  			false,
   113  		},
   114  		{
   115  			cty.NumberFloatVal(2),
   116  			cty.NumberFloatVal(-2),
   117  			cty.NumberFloatVal(0.25),
   118  			false,
   119  		},
   120  		{
   121  			cty.NumberFloatVal(0),
   122  			cty.NumberFloatVal(2),
   123  			cty.NumberFloatVal(0),
   124  			false,
   125  		},
   126  	}
   127  
   128  	for _, test := range tests {
   129  		t.Run(fmt.Sprintf("pow(%#v, %#v)", test.Num, test.Power), func(t *testing.T) {
   130  			got, err := Pow(test.Num, test.Power)
   131  
   132  			if test.Err {
   133  				if err == nil {
   134  					t.Fatal("succeeded; want error")
   135  				}
   136  				return
   137  			} else if err != nil {
   138  				t.Fatalf("unexpected error: %s", err)
   139  			}
   140  
   141  			if !got.RawEquals(test.Want) {
   142  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   143  			}
   144  		})
   145  	}
   146  }
   147  
   148  func TestSignum(t *testing.T) {
   149  	tests := []struct {
   150  		Num  cty.Value
   151  		Want cty.Value
   152  		Err  bool
   153  	}{
   154  		{
   155  			cty.NumberFloatVal(0),
   156  			cty.NumberFloatVal(0),
   157  			false,
   158  		},
   159  		{
   160  			cty.NumberFloatVal(12),
   161  			cty.NumberFloatVal(1),
   162  			false,
   163  		},
   164  		{
   165  			cty.NumberFloatVal(-29),
   166  			cty.NumberFloatVal(-1),
   167  			false,
   168  		},
   169  	}
   170  
   171  	for _, test := range tests {
   172  		t.Run(fmt.Sprintf("signum(%#v)", test.Num), func(t *testing.T) {
   173  			got, err := Signum(test.Num)
   174  
   175  			if test.Err {
   176  				if err == nil {
   177  					t.Fatal("succeeded; want error")
   178  				}
   179  				return
   180  			} else if err != nil {
   181  				t.Fatalf("unexpected error: %s", err)
   182  			}
   183  
   184  			if !got.RawEquals(test.Want) {
   185  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   186  			}
   187  		})
   188  	}
   189  }
   190  
   191  func TestParseInt(t *testing.T) {
   192  	tests := []struct {
   193  		Num  cty.Value
   194  		Base cty.Value
   195  		Want cty.Value
   196  		Err  string
   197  	}{
   198  		{
   199  			cty.StringVal("128"),
   200  			cty.NumberIntVal(10),
   201  			cty.NumberIntVal(128),
   202  			``,
   203  		},
   204  		{
   205  			cty.StringVal("128").Mark(marks.Sensitive),
   206  			cty.NumberIntVal(10),
   207  			cty.NumberIntVal(128).Mark(marks.Sensitive),
   208  			``,
   209  		},
   210  		{
   211  			cty.StringVal("128"),
   212  			cty.NumberIntVal(10).Mark(marks.Sensitive),
   213  			cty.NumberIntVal(128).Mark(marks.Sensitive),
   214  			``,
   215  		},
   216  		{
   217  			cty.StringVal("128").Mark(marks.Sensitive),
   218  			cty.NumberIntVal(10).Mark(marks.Sensitive),
   219  			cty.NumberIntVal(128).Mark(marks.Sensitive),
   220  			``,
   221  		},
   222  		{
   223  			cty.StringVal("128").Mark("boop"),
   224  			cty.NumberIntVal(10).Mark(marks.Sensitive),
   225  			cty.NumberIntVal(128).WithMarks(cty.NewValueMarks("boop", marks.Sensitive)),
   226  			``,
   227  		},
   228  		{
   229  			cty.StringVal("-128"),
   230  			cty.NumberIntVal(10),
   231  			cty.NumberIntVal(-128),
   232  			``,
   233  		},
   234  		{
   235  			cty.StringVal("00128"),
   236  			cty.NumberIntVal(10),
   237  			cty.NumberIntVal(128),
   238  			``,
   239  		},
   240  		{
   241  			cty.StringVal("-00128"),
   242  			cty.NumberIntVal(10),
   243  			cty.NumberIntVal(-128),
   244  			``,
   245  		},
   246  		{
   247  			cty.StringVal("FF00"),
   248  			cty.NumberIntVal(16),
   249  			cty.NumberIntVal(65280),
   250  			``,
   251  		},
   252  		{
   253  			cty.StringVal("ff00"),
   254  			cty.NumberIntVal(16),
   255  			cty.NumberIntVal(65280),
   256  			``,
   257  		},
   258  		{
   259  			cty.StringVal("-FF00"),
   260  			cty.NumberIntVal(16),
   261  			cty.NumberIntVal(-65280),
   262  			``,
   263  		},
   264  		{
   265  			cty.StringVal("00FF00"),
   266  			cty.NumberIntVal(16),
   267  			cty.NumberIntVal(65280),
   268  			``,
   269  		},
   270  		{
   271  			cty.StringVal("-00FF00"),
   272  			cty.NumberIntVal(16),
   273  			cty.NumberIntVal(-65280),
   274  			``,
   275  		},
   276  		{
   277  			cty.StringVal("1011111011101111"),
   278  			cty.NumberIntVal(2),
   279  			cty.NumberIntVal(48879),
   280  			``,
   281  		},
   282  		{
   283  			cty.StringVal("aA"),
   284  			cty.NumberIntVal(62),
   285  			cty.NumberIntVal(656),
   286  			``,
   287  		},
   288  		{
   289  			cty.StringVal("Aa"),
   290  			cty.NumberIntVal(62),
   291  			cty.NumberIntVal(2242),
   292  			``,
   293  		},
   294  		{
   295  			cty.StringVal("999999999999999999999999999999999999999999999999999999999999"),
   296  			cty.NumberIntVal(10),
   297  			cty.MustParseNumberVal("999999999999999999999999999999999999999999999999999999999999"),
   298  			``,
   299  		},
   300  		{
   301  			cty.StringVal("FF"),
   302  			cty.NumberIntVal(10),
   303  			cty.UnknownVal(cty.Number),
   304  			`cannot parse "FF" as a base 10 integer`,
   305  		},
   306  		{
   307  			cty.StringVal("FF").Mark(marks.Sensitive),
   308  			cty.NumberIntVal(10),
   309  			cty.UnknownVal(cty.Number),
   310  			`cannot parse (sensitive value) as a base 10 integer`,
   311  		},
   312  		{
   313  			cty.StringVal("FF").Mark(marks.Sensitive),
   314  			cty.NumberIntVal(10).Mark(marks.Sensitive),
   315  			cty.UnknownVal(cty.Number),
   316  			`cannot parse (sensitive value) as a base (sensitive value) integer`,
   317  		},
   318  		{
   319  			cty.StringVal("00FF"),
   320  			cty.NumberIntVal(10),
   321  			cty.UnknownVal(cty.Number),
   322  			`cannot parse "00FF" as a base 10 integer`,
   323  		},
   324  		{
   325  			cty.StringVal("-00FF"),
   326  			cty.NumberIntVal(10),
   327  			cty.UnknownVal(cty.Number),
   328  			`cannot parse "-00FF" as a base 10 integer`,
   329  		},
   330  		{
   331  			cty.NumberIntVal(2),
   332  			cty.NumberIntVal(10),
   333  			cty.UnknownVal(cty.Number),
   334  			`first argument must be a string, not number`,
   335  		},
   336  		{
   337  			cty.StringVal("1"),
   338  			cty.NumberIntVal(63),
   339  			cty.UnknownVal(cty.Number),
   340  			`base must be a whole number between 2 and 62 inclusive`,
   341  		},
   342  		{
   343  			cty.StringVal("1"),
   344  			cty.NumberIntVal(-1),
   345  			cty.UnknownVal(cty.Number),
   346  			`base must be a whole number between 2 and 62 inclusive`,
   347  		},
   348  		{
   349  			cty.StringVal("1"),
   350  			cty.NumberIntVal(1),
   351  			cty.UnknownVal(cty.Number),
   352  			`base must be a whole number between 2 and 62 inclusive`,
   353  		},
   354  		{
   355  			cty.StringVal("1"),
   356  			cty.NumberIntVal(0),
   357  			cty.UnknownVal(cty.Number),
   358  			`base must be a whole number between 2 and 62 inclusive`,
   359  		},
   360  		{
   361  			cty.StringVal("1.2"),
   362  			cty.NumberIntVal(10),
   363  			cty.UnknownVal(cty.Number),
   364  			`cannot parse "1.2" as a base 10 integer`,
   365  		},
   366  	}
   367  
   368  	for _, test := range tests {
   369  		t.Run(fmt.Sprintf("parseint(%#v, %#v)", test.Num, test.Base), func(t *testing.T) {
   370  			got, err := ParseInt(test.Num, test.Base)
   371  
   372  			if test.Err != "" {
   373  				if err == nil {
   374  					t.Fatal("succeeded; want error")
   375  				}
   376  				if got, want := err.Error(), test.Err; got != want {
   377  					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
   378  				}
   379  				return
   380  			} else if err != nil {
   381  				t.Fatalf("unexpected error: %s", err)
   382  			}
   383  
   384  			if !got.RawEquals(test.Want) {
   385  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   386  			}
   387  		})
   388  	}
   389  }