1package stdlib 2 3import ( 4 "testing" 5 6 "github.com/zclconf/go-cty/cty" 7) 8 9func TestUpper(t *testing.T) { 10 tests := []struct { 11 Input cty.Value 12 Want cty.Value 13 }{ 14 { 15 cty.StringVal("hello"), 16 cty.StringVal("HELLO"), 17 }, 18 { 19 cty.StringVal("HELLO"), 20 cty.StringVal("HELLO"), 21 }, 22 { 23 cty.StringVal(""), 24 cty.StringVal(""), 25 }, 26 { 27 cty.StringVal("1"), 28 cty.StringVal("1"), 29 }, 30 { 31 cty.StringVal("жж"), 32 cty.StringVal("ЖЖ"), 33 }, 34 { 35 cty.StringVal("noël"), 36 cty.StringVal("NOËL"), 37 }, 38 { 39 // Go's case conversions don't handle this ligature, which is 40 // unfortunate but is now a compatibility constraint since it 41 // would be potentially-breaking to behave differently here in 42 // future. 43 cty.StringVal("baffle"), 44 cty.StringVal("BAfflE"), 45 }, 46 { 47 cty.StringVal(""), 48 cty.StringVal(""), 49 }, 50 { 51 cty.UnknownVal(cty.String), 52 cty.UnknownVal(cty.String), 53 }, 54 { 55 cty.DynamicVal, 56 cty.UnknownVal(cty.String), 57 }, 58 { 59 cty.StringVal("hello").Mark(1), 60 cty.StringVal("HELLO").Mark(1), 61 }, 62 } 63 64 for _, test := range tests { 65 t.Run(test.Input.GoString(), func(t *testing.T) { 66 got, err := Upper(test.Input) 67 68 if err != nil { 69 t.Fatalf("unexpected error: %s", err) 70 } 71 72 if !got.RawEquals(test.Want) { 73 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 74 } 75 }) 76 } 77} 78 79func TestLower(t *testing.T) { 80 tests := []struct { 81 Input cty.Value 82 Want cty.Value 83 }{ 84 { 85 cty.StringVal("HELLO"), 86 cty.StringVal("hello"), 87 }, 88 { 89 cty.StringVal("hello"), 90 cty.StringVal("hello"), 91 }, 92 { 93 cty.StringVal(""), 94 cty.StringVal(""), 95 }, 96 { 97 cty.StringVal("1"), 98 cty.StringVal("1"), 99 }, 100 { 101 cty.StringVal("ЖЖ"), 102 cty.StringVal("жж"), 103 }, 104 { 105 cty.UnknownVal(cty.String), 106 cty.UnknownVal(cty.String), 107 }, 108 { 109 cty.DynamicVal, 110 cty.UnknownVal(cty.String), 111 }, 112 } 113 114 for _, test := range tests { 115 t.Run(test.Input.GoString(), func(t *testing.T) { 116 got, err := Lower(test.Input) 117 118 if err != nil { 119 t.Fatalf("unexpected error: %s", err) 120 } 121 122 if !got.RawEquals(test.Want) { 123 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 124 } 125 }) 126 } 127} 128 129func TestReverse(t *testing.T) { 130 tests := []struct { 131 Input cty.Value 132 Want cty.Value 133 }{ 134 { 135 cty.StringVal("hello"), 136 cty.StringVal("olleh"), 137 }, 138 { 139 cty.StringVal(""), 140 cty.StringVal(""), 141 }, 142 { 143 cty.StringVal("1"), 144 cty.StringVal("1"), 145 }, 146 { 147 cty.StringVal("Живой Журнал"), 148 cty.StringVal("ланруЖ йовиЖ"), 149 }, 150 { 151 // note that the dieresis here is intentionally a combining 152 // ligature. 153 cty.StringVal("noël"), 154 cty.StringVal("lëon"), 155 }, 156 { 157 // The Es in this string has three combining acute accents. 158 // This tests something that NFC-normalization cannot collapse 159 // into a single precombined codepoint, since otherwise we might 160 // be cheating and relying on the single-codepoint forms. 161 cty.StringVal("wé́́é́́é́́!"), 162 cty.StringVal("!é́́é́́é́́w"), 163 }, 164 { 165 // Go's normalization forms don't handle this ligature, so we 166 // will produce the wrong result but this is now a compatibility 167 // constraint and so we'll test it. 168 cty.StringVal("baffle"), 169 cty.StringVal("efflab"), 170 }, 171 { 172 cty.StringVal(""), 173 cty.StringVal(""), 174 }, 175 { 176 cty.UnknownVal(cty.String), 177 cty.UnknownVal(cty.String), 178 }, 179 { 180 cty.DynamicVal, 181 cty.UnknownVal(cty.String), 182 }, 183 } 184 185 for _, test := range tests { 186 t.Run(test.Input.GoString(), func(t *testing.T) { 187 got, err := Reverse(test.Input) 188 189 if err != nil { 190 t.Fatalf("unexpected error: %s", err) 191 } 192 193 if !got.RawEquals(test.Want) { 194 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 195 } 196 }) 197 } 198} 199 200func TestStrlen(t *testing.T) { 201 tests := []struct { 202 Input cty.Value 203 Want cty.Value 204 }{ 205 { 206 cty.StringVal("hello"), 207 cty.NumberIntVal(5), 208 }, 209 { 210 cty.StringVal(""), 211 cty.NumberIntVal(0), 212 }, 213 { 214 cty.StringVal("1"), 215 cty.NumberIntVal(1), 216 }, 217 { 218 cty.StringVal("Живой Журнал"), 219 cty.NumberIntVal(12), 220 }, 221 { 222 // note that the dieresis here is intentionally a combining 223 // ligature. 224 cty.StringVal("noël"), 225 cty.NumberIntVal(4), 226 }, 227 { 228 // The Es in this string has three combining acute accents. 229 // This tests something that NFC-normalization cannot collapse 230 // into a single precombined codepoint, since otherwise we might 231 // be cheating and relying on the single-codepoint forms. 232 cty.StringVal("wé́́é́́é́́!"), 233 cty.NumberIntVal(5), 234 }, 235 { 236 // Go's normalization forms don't handle this ligature, so we 237 // will produce the wrong result but this is now a compatibility 238 // constraint and so we'll test it. 239 cty.StringVal("baffle"), 240 cty.NumberIntVal(4), 241 }, 242 { 243 cty.StringVal(""), 244 cty.NumberIntVal(2), 245 }, 246 { 247 cty.UnknownVal(cty.String), 248 cty.UnknownVal(cty.Number), 249 }, 250 { 251 cty.DynamicVal, 252 cty.UnknownVal(cty.Number), 253 }, 254 } 255 256 for _, test := range tests { 257 t.Run(test.Input.GoString(), func(t *testing.T) { 258 got, err := Strlen(test.Input) 259 260 if err != nil { 261 t.Fatalf("unexpected error: %s", err) 262 } 263 264 if !got.RawEquals(test.Want) { 265 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 266 } 267 }) 268 } 269} 270 271func TestSubstr(t *testing.T) { 272 tests := []struct { 273 Input cty.Value 274 Offset cty.Value 275 Length cty.Value 276 Want cty.Value 277 }{ 278 { 279 cty.StringVal("hello"), 280 cty.NumberIntVal(0), 281 cty.NumberIntVal(2), 282 cty.StringVal("he"), 283 }, 284 { 285 cty.StringVal("hello"), 286 cty.NumberIntVal(1), 287 cty.NumberIntVal(3), 288 cty.StringVal("ell"), 289 }, 290 { 291 cty.StringVal("hello"), 292 cty.NumberIntVal(1), 293 cty.NumberIntVal(-1), 294 cty.StringVal("ello"), 295 }, 296 { 297 cty.StringVal("hello"), 298 cty.NumberIntVal(1), 299 cty.NumberIntVal(-10), // not documented, but <0 is the same as -1 300 cty.StringVal("ello"), 301 }, 302 { 303 cty.StringVal("hello"), 304 cty.NumberIntVal(1), 305 cty.NumberIntVal(10), 306 cty.StringVal("ello"), 307 }, 308 { 309 cty.StringVal("hello"), 310 cty.NumberIntVal(-3), 311 cty.NumberIntVal(-1), 312 cty.StringVal("llo"), 313 }, 314 { 315 cty.StringVal("hello"), 316 cty.NumberIntVal(-3), 317 cty.NumberIntVal(2), 318 cty.StringVal("ll"), 319 }, 320 { 321 cty.StringVal("hello"), 322 cty.NumberIntVal(10), 323 cty.NumberIntVal(10), 324 cty.StringVal(""), 325 }, 326 { 327 cty.StringVal("hello"), 328 cty.NumberIntVal(0), 329 cty.NumberIntVal(0), 330 cty.StringVal(""), 331 }, 332 { 333 cty.StringVal("noël"), 334 cty.NumberIntVal(0), 335 cty.NumberIntVal(3), 336 cty.StringVal("noë"), 337 }, 338 { 339 cty.StringVal("noël"), 340 cty.NumberIntVal(3), 341 cty.NumberIntVal(-1), 342 cty.StringVal("l"), 343 }, 344 { 345 cty.StringVal("wé́́é́́é́́!"), 346 cty.NumberIntVal(2), 347 cty.NumberIntVal(2), 348 cty.StringVal("é́́é́́"), 349 }, 350 { 351 cty.StringVal("wé́́é́́é́́!"), 352 cty.NumberIntVal(3), 353 cty.NumberIntVal(2), 354 cty.StringVal("é́́!"), 355 }, 356 { 357 cty.StringVal("wé́́é́́é́́!"), 358 cty.NumberIntVal(-2), 359 cty.NumberIntVal(-1), 360 cty.StringVal("é́́!"), 361 }, 362 { 363 cty.StringVal("noël"), 364 cty.NumberIntVal(-2), 365 cty.NumberIntVal(-1), 366 cty.StringVal("ël"), 367 }, 368 { 369 cty.StringVal(""), 370 cty.NumberIntVal(0), 371 cty.NumberIntVal(1), 372 cty.StringVal(""), 373 }, 374 { 375 cty.StringVal(""), 376 cty.NumberIntVal(1), 377 cty.NumberIntVal(1), 378 cty.StringVal(""), 379 }, 380 } 381 382 for _, test := range tests { 383 t.Run(test.Input.GoString(), func(t *testing.T) { 384 got, err := Substr(test.Input, test.Offset, test.Length) 385 386 if err != nil { 387 t.Fatalf("unexpected error: %s", err) 388 } 389 390 if !got.RawEquals(test.Want) { 391 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 392 } 393 }) 394 } 395} 396 397func TestJoin(t *testing.T) { 398 tests := map[string]struct { 399 Separator cty.Value 400 Lists []cty.Value 401 Want cty.Value 402 }{ 403 "single two-element list": { 404 cty.StringVal("-"), 405 []cty.Value{ 406 cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}), 407 }, 408 cty.StringVal("hello-world"), 409 }, 410 "multiple single-element lists": { 411 cty.StringVal("-"), 412 []cty.Value{ 413 cty.ListVal([]cty.Value{cty.StringVal("chicken")}), 414 cty.ListVal([]cty.Value{cty.StringVal("egg")}), 415 }, 416 cty.StringVal("chicken-egg"), 417 }, 418 "single single-element list": { 419 cty.StringVal("-"), 420 []cty.Value{ 421 cty.ListVal([]cty.Value{cty.StringVal("chicken")}), 422 }, 423 cty.StringVal("chicken"), 424 }, 425 "blank separator": { 426 cty.StringVal(""), 427 []cty.Value{ 428 cty.ListVal([]cty.Value{cty.StringVal("horse"), cty.StringVal("face")}), 429 }, 430 cty.StringVal("horseface"), 431 }, 432 "marked list": { 433 cty.StringVal("-"), 434 []cty.Value{ 435 cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("sensitive"), 436 }, 437 cty.StringVal("hello-world").Mark("sensitive"), 438 }, 439 "marked separator": { 440 cty.StringVal("-").Mark("sensitive"), 441 []cty.Value{ 442 cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}), 443 }, 444 cty.StringVal("hello-world").Mark("sensitive"), 445 }, 446 "list with some marked elements": { 447 cty.StringVal("-"), 448 []cty.Value{ 449 cty.ListVal([]cty.Value{cty.StringVal("hello").Mark("sensitive"), cty.StringVal("world")}), 450 }, 451 cty.StringVal("hello-world").Mark("sensitive"), 452 }, 453 "multiple marks": { 454 cty.StringVal("-").Mark("a"), 455 []cty.Value{ 456 cty.ListVal([]cty.Value{cty.StringVal("hello").Mark("b"), cty.StringVal("world").Mark("c")}), 457 }, 458 cty.StringVal("hello-world").WithMarks(cty.NewValueMarks("a", "b", "c")), 459 }, 460 } 461 462 for name, test := range tests { 463 t.Run(name, func(t *testing.T) { 464 got, err := Join(test.Separator, test.Lists...) 465 466 if err != nil { 467 t.Fatalf("unexpected error: %s", err) 468 } 469 470 if !got.RawEquals(test.Want) { 471 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 472 } 473 }) 474 } 475} 476