go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/testdata/misc/validators.star (about)

     1  load("@stdlib//internal/time.star", "time")
     2  load("@stdlib//internal/validate.star", "validate")
     3  
     4  def test_validate_string():
     5      call = validate.string
     6      assert.eq(call("a", "zzz"), "zzz")
     7      assert.eq(call("a", "abc", regexp = "a.c$"), "abc")
     8      assert.eq(call("a", "", default = "zzz", allow_empty = True, required = False), "")
     9      assert.eq(call("a", None, default = "zzz", allow_empty = True, required = False), "zzz")
    10      assert.eq(call("a", None, required = False), None)
    11      assert.fails(lambda: call("a", None), 'missing required field "a"')
    12      assert.fails(lambda: call("a", 1), 'bad "a": got int, want string')
    13      assert.fails(lambda: call("a", []), 'bad "a": got list, want string')
    14      assert.fails(lambda: call("a", None, default = 1, required = False), 'bad "a": got int, want string')
    15      assert.fails(lambda: call("a", "abcd", regexp = "a.c$"), r'bad "a": "abcd" should match "a\.c\$"')
    16      assert.fails(lambda: call("a", "", default = "zzz", required = False), 'bad "a": must not be empty')
    17  
    18  def test_validate_hostname():
    19      call = validate.hostname
    20      assert.eq(call("a", "zzz"), "zzz")
    21      assert.eq(call("a", "test-domain.example.com"), "test-domain.example.com")
    22      assert.eq(call("a", "xn--ls8h.example.com"), "xn--ls8h.example.com")
    23      assert.eq(call("a", None, default = "zzz", required = False), "zzz")
    24      assert.eq(call("a", None, required = False), None)
    25  
    26      assert.fails(lambda: call("a", None), 'missing required field "a"')
    27      assert.fails(lambda: call("a", 1), 'bad "a": got int, want string')
    28      assert.fails(lambda: call("a", []), 'bad "a": got list, want string')
    29      assert.fails(lambda: call("a", None, default = 1, required = False), 'bad "a": got int, want string')
    30      assert.fails(lambda: call("a", "!notdomain"), r'bad "a": "!notdomain" is not valid RFC1123 hostname')
    31      assert.fails(
    32          lambda: call("a", "https://i.am.a.url.example.com"),
    33          r'bad "a": "https://i.am.a.url.example.com" is not valid RFC1123 hostname',
    34      )
    35      assert.fails(lambda: call("a", "", default = "zzz", required = False), 'bad "a": must not be empty')
    36  
    37  def test_validate_int():
    38      call = validate.int
    39      assert.eq(call("a", 123, min = 123, max = 123), 123)
    40      assert.eq(call("a", 0, default = 123, required = False), 0)
    41      assert.eq(call("a", None, default = 123, required = False), 123)
    42      assert.eq(call("a", None, required = False), None)
    43      assert.fails(lambda: call("a", None), 'missing required field "a"')
    44      assert.fails(lambda: call("a", "1"), 'bad "a": got string, want int')
    45      assert.fails(lambda: call("a", []), 'bad "a": got list, want int')
    46      assert.fails(lambda: call("a", None, default = "1", required = False), 'bad "a": got string, want int')
    47      assert.fails(lambda: call("a", 123, min = 124), 'bad "a": 123 should be >= 124')
    48      assert.fails(lambda: call("a", 123, max = 122), 'bad "a": 123 should be <= 122')
    49  
    50  def test_validate_float():
    51      call = validate.float
    52      assert.eq(call("a", 123.4, min = 123, max = 123.5), 123.4)
    53      assert.eq(call("a", 123, min = 123, max = 123), 123.0)
    54      assert.eq(call("a", 0, default = 123, required = False), 0.0)
    55      assert.eq(call("a", None, default = 123, required = False), 123.0)
    56      assert.eq(call("a", None, required = False), None)
    57      assert.fails(lambda: call("a", None), 'missing required field "a"')
    58      assert.fails(lambda: call("a", "1"), 'bad "a": got string, want float or int')
    59      assert.fails(lambda: call("a", []), 'bad "a": got list, want float or int')
    60      assert.fails(lambda: call("a", None, default = "1", required = False), 'bad "a": got string, want float or int')
    61      assert.fails(lambda: call("a", 123, min = 124.5), 'bad "a": 123.0 should be >= 124.5')
    62      assert.fails(lambda: call("a", 123, max = 122.5), 'bad "a": 123.0 should be <= 122.5')
    63  
    64  def test_validate_bool():
    65      call = validate.bool
    66      assert.eq(call("a", True), True)
    67      assert.eq(call("a", 1), True)
    68      assert.eq(call("a", [1]), True)
    69      assert.eq(call("a", []), False)
    70      assert.eq(call("a", None, default = True, required = False), True)
    71      assert.eq(call("a", None, default = False, required = False), False)
    72      assert.eq(call("a", None, required = False), None)
    73      assert.fails(lambda: call("a", None), 'missing required field "a"')
    74  
    75  def test_validate_duration():
    76      call = validate.duration
    77      m = time.minute
    78      assert.eq(call("a", m), m)
    79      assert.eq(call("a", None, default = m, required = False), m)
    80      assert.eq(call("a", None, required = False), None)
    81      assert.fails(lambda: call("a", None), 'missing required field "a"')
    82      assert.fails(lambda: call("a", 1), 'bad "a": got int, want duration')
    83      assert.fails(lambda: call("a", []), 'bad "a": got list, want duration')
    84      assert.fails(lambda: call("a", -m), 'bad "a": -1m0s should be >= 0s')
    85      assert.fails(lambda: call("a", 2 * m, max = m), 'bad "a": 2m0s should be <= 1m0s')
    86      assert.fails(
    87          lambda: call("a", 500 * time.millisecond),
    88          'bad "a": losing precision when truncating 500ms to 1s units, use ' +
    89          r"time.truncate\(\.\.\.\) to acknowledge",
    90      )
    91  
    92  def test_validate_list():
    93      call = validate.list
    94      assert.eq(call("a", [1, "a"]), [1, "a"])
    95      assert.eq(call("a", []), [])
    96      assert.eq(call("a", None), [])
    97      assert.fails(lambda: call("a", 0), 'bad "a": got int, want list')
    98      assert.fails(lambda: call("a", {}), 'bad "a": got dict, want list')
    99      assert.fails(lambda: call("a", None, required = True), 'missing required field "a"')
   100      assert.fails(lambda: call("a", [], required = True), 'missing required field "a"')
   101  
   102  def test_validate_str_dict():
   103      call = validate.str_dict
   104      assert.eq(call("a", {"k": 1}), {"k": 1})
   105      assert.eq(call("a", {}), {})
   106      assert.eq(call("a", None), {})
   107      assert.fails(lambda: call("a", 0), 'bad "a": got int, want dict')
   108      assert.fails(lambda: call("a", []), 'bad "a": got list, want dict')
   109      assert.fails(lambda: call("a", {1: 1}), 'bad "a": got int key, want string')
   110      assert.fails(lambda: call("a", {"": 1}), 'bad "a": got empty key')
   111      assert.fails(lambda: call("a", None, required = True), 'missing required field "a"')
   112      assert.fails(lambda: call("a", {}, required = True), 'missing required field "a"')
   113  
   114  def test_validate_struct():
   115      call = validate.struct
   116      s = struct(a = 1, b = 2)
   117      assert.eq(call("a", s, "struct"), s)
   118      assert.eq(call("a", None, "struct", default = s, required = False), s)
   119      assert.eq(call("a", None, "struct", required = False), None)
   120      assert.fails(lambda: call("a", None, "struct"), 'missing required field "a"')
   121      assert.fails(lambda: call("a", 1, "struct"), 'bad "a": got int, want struct')
   122      assert.fails(lambda: call("a", [], "struct"), 'bad "a": got list, want struct')
   123      assert.fails(lambda: call("a", None, "struct", default = 1, required = False), 'bad "a": got int, want struct')
   124  
   125  def test_validate_type():
   126      call = validate.type
   127      assert.eq(call("a", 1, 0), 1)
   128      assert.eq(call("a", None, 0, default = 123, required = False), 123)
   129      assert.eq(call("a", None, 0, required = False), None)
   130      assert.fails(lambda: call("a", None, 0), 'missing required field "a"')
   131      assert.fails(lambda: call("a", "sss", 0), 'bad "a": got string, want int')
   132      assert.fails(lambda: call("a", [], 0), 'bad "a": got list, want int')
   133  
   134  def test_validate_relative_path():
   135      call = validate.relative_path
   136      assert.eq(call("a", "./abc/def//./zzz/../yyy/."), "abc/def/yyy")
   137      assert.eq(call("a", "."), ".")
   138      assert.eq(call("a", "./../abc", allow_dots = True), "../abc")
   139      assert.eq(call("a", None, required = False), None)
   140      assert.fails(lambda: call("a", None), 'missing required field "a"')
   141      assert.fails(lambda: call("a", "./../abc"), 'must not start with "../"')
   142      assert.fails(lambda: call("a", "a/../../abc"), 'must not start with "../"')
   143  
   144      # Rebasing.
   145      assert.eq(call("a", "./abc", base = "./a/b"), "a/b/abc")
   146      assert.eq(call("a", "../abc", base = "./a/b"), "a/abc")
   147      assert.eq(call("a", "../../abc", base = "./a/b"), "abc")
   148      assert.eq(call("a", "../../../abc", base = "./a/b", allow_dots = True), "../abc")
   149      assert.fails(
   150          lambda: call("a", "../../../abc", base = "./a/b", allow_dots = False),
   151          'must not start with "../"',
   152      )
   153      assert.fails(
   154          lambda: call("a", "a/../../../../abc", base = "./a/b", allow_dots = False),
   155          'must not start with "../"',
   156      )
   157  
   158  def test_validate_regex_list():
   159      call = validate.regex_list
   160  
   161      assert.fails(lambda: call("a", 123), 'bad "a": got int, want string or list')
   162      assert.fails(lambda: call("a", [123]), 'bad "a": got list element of type int, want string')
   163      assert.fails(lambda: call("a", None, required = True), 'missing required field "a"')
   164      assert.fails(lambda: call("a", "", required = True), 'missing required field "a"')
   165      assert.fails(lambda: call("a", [], required = True), 'missing required field "a"')
   166      assert.fails(lambda: call("a", "("), 'bad "a": error parsing regexp: missing closing \\): `\\(`')
   167      assert.fails(lambda: call("a", ["(ab", "bc)"]), 'bad "a": error parsing regexp: missing closing \\): `\\(ab`')
   168  
   169      assert.eq(call("a", ""), "")
   170      assert.eq(call("a", []), "")
   171      assert.eq(call("a", "abc.*def"), "abc.*def")
   172      assert.eq(call("a", "abcdef", required = True), "abcdef")
   173      assert.eq(call("a", ["xyz", "abc"]), "xyz|abc")
   174      assert.eq(call("a", ["xyz", "abc"], required = True), "xyz|abc")
   175      assert.eq(call("a", ["x.*yz", "defg", "abc"]), "x.*yz|defg|abc")
   176  
   177  def test_validate_str_list():
   178      call = validate.str_list
   179      assert.eq(call("a", ["a", "b"]), ["a", "b"])
   180      assert.eq(call("a", []), [])
   181      assert.eq(call("a", None), [])
   182      assert.fails(lambda: call("a", 0), 'bad "a": got int, want list')
   183      assert.fails(lambda: call("a", {}), 'bad "a": got dict, want list')
   184      assert.fails(lambda: call("a", [100]), 'bad "a": got list element of type int, want string')
   185      assert.fails(lambda: call("a", None, required = True), 'missing required field "a"')
   186      assert.fails(lambda: call("a", [], required = True), 'missing required field "a"')
   187  
   188  test_validate_string()
   189  test_validate_hostname()
   190  test_validate_int()
   191  test_validate_float()
   192  test_validate_bool()
   193  test_validate_duration()
   194  test_validate_list()
   195  test_validate_str_dict()
   196  test_validate_struct()
   197  test_validate_type()
   198  test_validate_relative_path()
   199  test_validate_regex_list()
   200  test_validate_str_list()