github.com/opentofu/opentofu@v1.7.1/internal/lang/funcs/datetime_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 "time" 12 13 "github.com/zclconf/go-cty/cty" 14 ) 15 16 func TestTimestamp(t *testing.T) { 17 currentTime := time.Now().UTC() 18 result, err := Timestamp() 19 if err != nil { 20 t.Fatalf("err: %s", err) 21 } 22 resultTime, err := time.Parse(time.RFC3339, result.AsString()) 23 if err != nil { 24 t.Fatalf("Error parsing timestamp: %s", err) 25 } 26 27 if resultTime.Sub(currentTime).Seconds() > 10.0 { 28 t.Fatalf("Timestamp Diff too large. Expected: %s\nReceived: %s", currentTime.Format(time.RFC3339), result.AsString()) 29 } 30 31 } 32 33 func TestTimeadd(t *testing.T) { 34 tests := []struct { 35 Time cty.Value 36 Duration cty.Value 37 Want cty.Value 38 Err bool 39 }{ 40 { 41 cty.StringVal("2017-11-22T00:00:00Z"), 42 cty.StringVal("1s"), 43 cty.StringVal("2017-11-22T00:00:01Z"), 44 false, 45 }, 46 { 47 cty.StringVal("2017-11-22T00:00:00Z"), 48 cty.StringVal("10m1s"), 49 cty.StringVal("2017-11-22T00:10:01Z"), 50 false, 51 }, 52 { // also support subtraction 53 cty.StringVal("2017-11-22T00:00:00Z"), 54 cty.StringVal("-1h"), 55 cty.StringVal("2017-11-21T23:00:00Z"), 56 false, 57 }, 58 { // Invalid format timestamp 59 cty.StringVal("2017-11-22"), 60 cty.StringVal("-1h"), 61 cty.UnknownVal(cty.String).RefineNotNull(), 62 true, 63 }, 64 { // Invalid format duration (day is not supported by ParseDuration) 65 cty.StringVal("2017-11-22T00:00:00Z"), 66 cty.StringVal("1d"), 67 cty.UnknownVal(cty.String).RefineNotNull(), 68 true, 69 }, 70 } 71 72 for _, test := range tests { 73 t.Run(fmt.Sprintf("TimeAdd(%#v, %#v)", test.Time, test.Duration), func(t *testing.T) { 74 got, err := TimeAdd(test.Time, test.Duration) 75 76 if test.Err { 77 if err == nil { 78 t.Fatal("succeeded; want error") 79 } 80 return 81 } else if err != nil { 82 t.Fatalf("unexpected error: %s", err) 83 } 84 85 if !got.RawEquals(test.Want) { 86 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 87 } 88 }) 89 } 90 } 91 92 func TestTimeCmp(t *testing.T) { 93 tests := []struct { 94 TimeA, TimeB cty.Value 95 Want cty.Value 96 Err string 97 }{ 98 { 99 cty.StringVal("2017-11-22T00:00:00Z"), 100 cty.StringVal("2017-11-22T00:00:00Z"), 101 cty.Zero, 102 ``, 103 }, 104 { 105 cty.StringVal("2017-11-22T00:00:00Z"), 106 cty.StringVal("2017-11-22T01:00:00+01:00"), 107 cty.Zero, 108 ``, 109 }, 110 { 111 cty.StringVal("2017-11-22T00:00:01Z"), 112 cty.StringVal("2017-11-22T01:00:00+01:00"), 113 cty.NumberIntVal(1), 114 ``, 115 }, 116 { 117 cty.StringVal("2017-11-22T01:00:00Z"), 118 cty.StringVal("2017-11-22T00:59:00-01:00"), 119 cty.NumberIntVal(-1), 120 ``, 121 }, 122 { 123 cty.StringVal("2017-11-22T01:00:00+01:00"), 124 cty.StringVal("2017-11-22T01:00:00-01:00"), 125 cty.NumberIntVal(-1), 126 ``, 127 }, 128 { 129 cty.StringVal("2017-11-22T01:00:00-01:00"), 130 cty.StringVal("2017-11-22T01:00:00+01:00"), 131 cty.NumberIntVal(1), 132 ``, 133 }, 134 { 135 cty.StringVal("2017-11-22T00:00:00Z"), 136 cty.StringVal("bloop"), 137 cty.UnknownVal(cty.String).RefineNotNull(), 138 `not a valid RFC3339 timestamp: cannot use "bloop" as year`, 139 }, 140 { 141 cty.StringVal("2017-11-22 00:00:00Z"), 142 cty.StringVal("2017-11-22T00:00:00Z"), 143 cty.UnknownVal(cty.String).RefineNotNull(), 144 `not a valid RFC3339 timestamp: missing required time introducer 'T'`, 145 }, 146 { 147 cty.StringVal("2017-11-22T00:00:00Z"), 148 cty.UnknownVal(cty.String), 149 cty.UnknownVal(cty.Number).RefineNotNull(), 150 ``, 151 }, 152 { 153 cty.UnknownVal(cty.String), 154 cty.StringVal("2017-11-22T00:00:00Z"), 155 cty.UnknownVal(cty.Number).RefineNotNull(), 156 ``, 157 }, 158 { 159 cty.UnknownVal(cty.String), 160 cty.UnknownVal(cty.String), 161 cty.UnknownVal(cty.Number).RefineNotNull(), 162 ``, 163 }, 164 } 165 166 for _, test := range tests { 167 t.Run(fmt.Sprintf("TimeCmp(%#v, %#v)", test.TimeA, test.TimeB), func(t *testing.T) { 168 got, err := TimeCmp(test.TimeA, test.TimeB) 169 170 if test.Err != "" { 171 if err == nil { 172 t.Fatal("succeeded; want error") 173 } 174 if got := err.Error(); got != test.Err { 175 t.Errorf("wrong error message\ngot: %s\nwant: %s", got, test.Err) 176 } 177 return 178 } else if err != nil { 179 t.Fatalf("unexpected error: %s", err) 180 } 181 182 if !got.RawEquals(test.Want) { 183 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 184 } 185 }) 186 } 187 }