github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmn/cos/template_test.go (about) 1 // Package test provides tests for common low-level types and utilities for all aistore projects 2 /* 3 * Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package cos_test 6 7 import ( 8 "math" 9 10 "github.com/NVIDIA/aistore/cmn/cos" 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 ) 14 15 var _ = Describe("Template", func() { 16 Context("ParseFmtTemplate", func() { 17 DescribeTable("parse fmt template without error", 18 func(template string, expectedPt cos.ParsedTemplate) { 19 pt, err := cos.ParseFmtTemplate(template) 20 Expect(err).ShouldNot(HaveOccurred()) 21 Expect(pt).To(Equal(expectedPt)) 22 }, 23 Entry("simple", "%d", cos.ParsedTemplate{ 24 Prefix: "", 25 Ranges: []cos.TemplateRange{{ 26 Start: 0, 27 End: math.MaxInt64 - 1, 28 Step: 1, 29 DigitCount: 0, 30 Gap: "", 31 }}, 32 }), 33 Entry("with prefix", "prefix-%d", cos.ParsedTemplate{ 34 Prefix: "prefix-", 35 Ranges: []cos.TemplateRange{{ 36 Start: 0, 37 End: math.MaxInt64 - 1, 38 Step: 1, 39 DigitCount: 0, 40 Gap: "", 41 }}, 42 }), 43 Entry("with prefix and suffix", "prefix-%d-suffix", cos.ParsedTemplate{ 44 Prefix: "prefix-", 45 Ranges: []cos.TemplateRange{{ 46 Start: 0, 47 End: math.MaxInt64 - 1, 48 Step: 1, 49 DigitCount: 0, 50 Gap: "-suffix", 51 }}, 52 }), 53 Entry("with 0 digits", "prefix-%00d-suffix", cos.ParsedTemplate{ 54 Prefix: "prefix-", 55 Ranges: []cos.TemplateRange{{ 56 Start: 0, 57 End: math.MaxInt64 - 1, 58 Step: 1, 59 DigitCount: 0, 60 Gap: "-suffix", 61 }}, 62 }), 63 Entry("with multiple digits", "prefix-%06d-suffix", cos.ParsedTemplate{ 64 Prefix: "prefix-", 65 Ranges: []cos.TemplateRange{{ 66 Start: 0, 67 End: math.MaxInt64 - 1, 68 Step: 1, 69 DigitCount: 6, 70 Gap: "-suffix", 71 }}, 72 }), 73 Entry("with large number of digits", "prefix-%0152d-suffix", cos.ParsedTemplate{ 74 Prefix: "prefix-", 75 Ranges: []cos.TemplateRange{{ 76 Start: 0, 77 End: math.MaxInt64 - 1, 78 Step: 1, 79 DigitCount: 152, 80 Gap: "-suffix", 81 }}, 82 }), 83 ) 84 85 DescribeTable("parse fmt template with error", 86 func(template string) { 87 _, err := cos.ParseFmtTemplate(template) 88 Expect(err).Should(HaveOccurred()) 89 }, 90 Entry("missing %", "prefix-06d-suffix"), 91 Entry("missing d", "prefix-%06-suffix"), 92 Entry("% after d", "prefix-d%06-suffix"), 93 Entry("negative digits", "prefix-%0-6d-suffix"), 94 Entry("no digits specified", "prefix-%0d-suffix"), 95 Entry("no zero specified", "prefix-%6d-suffix"), 96 // Currently rejecting even if looks quite OK. 97 Entry("second %", "prefix-%06d-%"), 98 Entry("double %%", "prefix-%%06d-suffix"), 99 // Currently rejecting even if the second format is not used. 100 Entry("second format string", "prefix-%06d-%06d"), 101 ) 102 }) 103 104 Context("ParseBashTemplate", func() { 105 DescribeTable("parse bash template without error", 106 func(template string, expectedPt cos.ParsedTemplate) { 107 pt, err := cos.ParseBashTemplate(template) 108 Expect(err).ShouldNot(HaveOccurred()) 109 Expect(pt).To(Equal(expectedPt)) 110 }, 111 Entry("with step", "prefix-{0010..0111..2}-suffix", cos.ParsedTemplate{ 112 Prefix: "prefix-", 113 Ranges: []cos.TemplateRange{{ 114 Start: 10, 115 End: 111, 116 Step: 2, 117 DigitCount: 4, 118 Gap: "-suffix", 119 }}, 120 }), 121 Entry("without step and suffix", "prefix-{0010..0111}", cos.ParsedTemplate{ 122 Prefix: "prefix-", 123 Ranges: []cos.TemplateRange{{ 124 Start: 10, 125 End: 111, 126 Step: 1, 127 DigitCount: 4, 128 Gap: "", 129 }}, 130 }), 131 Entry("minimal", "{1..2}", cos.ParsedTemplate{ 132 Prefix: "", 133 Ranges: []cos.TemplateRange{{ 134 Start: 1, 135 End: 2, 136 Step: 1, 137 DigitCount: 1, 138 Gap: "", 139 }}, 140 }), 141 Entry("minimal multiple digits", "{110..220..10}", cos.ParsedTemplate{ 142 Prefix: "", 143 Ranges: []cos.TemplateRange{{ 144 Start: 110, 145 End: 220, 146 Step: 10, 147 DigitCount: 3, 148 Gap: "", 149 }}, 150 }), 151 Entry("minimal with digit count", "{1..02}", cos.ParsedTemplate{ 152 Prefix: "", 153 Ranges: []cos.TemplateRange{{ 154 Start: 1, 155 End: 2, 156 Step: 1, 157 DigitCount: 1, 158 Gap: "", 159 }}, 160 }), 161 Entry("minimal with special suffix", "{1..02}}", cos.ParsedTemplate{ 162 Prefix: "", 163 Ranges: []cos.TemplateRange{{ 164 Start: 1, 165 End: 2, 166 Step: 1, 167 DigitCount: 1, 168 Gap: "}", 169 }}, 170 }), 171 Entry("multi-range", "prefix-{0010..0111..2}-gap-{10..12}-gap2-{0040..0099..4}-suffix", cos.ParsedTemplate{ 172 Prefix: "prefix-", 173 Ranges: []cos.TemplateRange{ 174 { 175 Start: 10, 176 End: 111, 177 Step: 2, 178 DigitCount: 4, 179 Gap: "-gap-", 180 }, 181 { 182 Start: 10, 183 End: 12, 184 Step: 1, 185 DigitCount: 2, 186 Gap: "-gap2-", 187 }, 188 { 189 Start: 40, 190 End: 99, 191 Step: 4, 192 DigitCount: 4, 193 Gap: "-suffix", 194 }, 195 }, 196 }), 197 ) 198 199 DescribeTable("parse bash template with error", 200 func(template string) { 201 _, err := cos.ParseBashTemplate(template) 202 Expect(err).Should(HaveOccurred()) 203 }, 204 Entry("missing {", "prefix-0010..0111..2}-suffix"), 205 Entry("missing }", "prefix-{001..009-suffix"), 206 Entry("start after end", "prefix-{002..001}-suffix"), 207 Entry("negative start", "prefix-{-001..009}-suffix"), 208 Entry("negative step", "prefix-{001..009..-1}-suffix"), 209 Entry("invalid step", "prefix-{0010..0111..2s}-suffix"), 210 Entry("invalid end", "prefix-{0010..0111s..2}-suffix"), 211 Entry("invalid start", "prefix-{0010s..0111..2}-suffix"), 212 Entry("too many arms", "prefix-{00..10..0111..2}-suffix"), 213 Entry("missing end", "prefix-{010..}-suffix"), 214 Entry("missing start", "prefix-{..009}-suffix"), 215 Entry("missing start and end", "prefix-{..}-suffix"), 216 Entry("empty template with prefix and suffix", "prefix-{}-suffix"), 217 Entry("empty template", "{}"), 218 Entry("nested templates", "{{}}"), 219 Entry("nested templates with numbers", "{{1..2}}"), 220 Entry("interleaving templates", "{1..2{3..4}}"), 221 ) 222 }) 223 224 Context("ParseAtTemplate", func() { 225 DescribeTable("parse at template without error", 226 func(template string, expectedPt cos.ParsedTemplate) { 227 pt, err := cos.ParseAtTemplate(template) 228 Expect(err).ShouldNot(HaveOccurred()) 229 Expect(pt).To(Equal(expectedPt)) 230 }, 231 Entry("full featured template", "prefix-@010-suffix", cos.ParsedTemplate{ 232 Prefix: "prefix-", 233 Ranges: []cos.TemplateRange{{ 234 Start: 0, 235 End: 10, 236 Step: 1, 237 DigitCount: 3, 238 Gap: "-suffix", 239 }}, 240 }), 241 Entry("minimal with prefix", "pref@9", cos.ParsedTemplate{ 242 Prefix: "pref", 243 Ranges: []cos.TemplateRange{{ 244 Start: 0, 245 End: 9, 246 Step: 1, 247 DigitCount: 1, 248 Gap: "", 249 }}, 250 }), 251 Entry("minimal", "@0010", cos.ParsedTemplate{ 252 Prefix: "", 253 Ranges: []cos.TemplateRange{{ 254 Start: 0, 255 End: 10, 256 Step: 1, 257 DigitCount: 4, 258 Gap: "", 259 }}, 260 }), 261 Entry("multi-range", "pref@9-gap-@0100-suffix", cos.ParsedTemplate{ 262 Prefix: "pref", 263 Ranges: []cos.TemplateRange{ 264 { 265 Start: 0, 266 End: 9, 267 Step: 1, 268 DigitCount: 1, 269 Gap: "-gap-", 270 }, 271 { 272 Start: 0, 273 End: 100, 274 Step: 1, 275 DigitCount: 4, 276 Gap: "-suffix", 277 }, 278 }, 279 }), 280 ) 281 282 DescribeTable("parse at template with error", 283 func(template string) { 284 _, err := cos.ParseAtTemplate(template) 285 Expect(err).Should(HaveOccurred()) 286 }, 287 Entry("missing @", "prefix-01-suffix"), 288 Entry("negative end", "prefix-@-0001-suffix"), 289 Entry("repetitive @", "prefix-@@0010-suffix"), 290 Entry("non-digit range", "prefix-@d@0010-suffix"), 291 ) 292 }) 293 294 Context("ParsedTemplate", func() { 295 DescribeTable("iter method", 296 func(template string, expectedStrs ...string) { 297 pt, err := cos.ParseBashTemplate(template) 298 Expect(err).NotTo(HaveOccurred()) 299 300 var i int 301 pt.InitIter() 302 for str, hasNext := pt.Next(); hasNext; str, hasNext = pt.Next() { 303 Expect(str).To(Equal(expectedStrs[i])) 304 i++ 305 } 306 Expect(i).To(Equal(len(expectedStrs))) 307 Expect(i).To(Equal(int(pt.Count()))) 308 }, 309 Entry( 310 "simple template", "prefix-{0010..0013..2}-suffix", 311 "prefix-0010-suffix", "prefix-0012-suffix", 312 ), 313 Entry( 314 "multi-range template", "prefix-{0010..0013..2}-gap-{1..2}-suffix", 315 "prefix-0010-gap-1-suffix", "prefix-0010-gap-2-suffix", "prefix-0012-gap-1-suffix", "prefix-0012-gap-2-suffix", 316 ), 317 Entry( 318 "large step", "prefix-{0010..0013..2}-gap-{1..2..3}-suffix", 319 "prefix-0010-gap-1-suffix", "prefix-0012-gap-1-suffix", 320 ), 321 ) 322 }) 323 })