File: test.sh

package info (click to toggle)
crudini 0.9.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 284 kB
  • sloc: python: 938; sh: 586; makefile: 16
file content (718 lines) | stat: -rwxr-xr-x 27,581 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
#!/bin/bash

trap "exit 130" INT
cleanup() { rm -f err noequals*.ini test.ini ltest.ini good.ini example.ini; exit "$1"; }
trap 'cleanup $?' EXIT

crudini() { ../crudini.py "$@"; }

test=0

fail() {
  test=$(($test+1))
  printf "Test $test \033[1;31mFAIL\033[m (line ${BASH_LINENO[0]})\n"
  exit 1
}
ok() { test=$(($test+1)); echo "Test $test OK (line ${BASH_LINENO[0]})"; }

cp ../example.ini .

# invalid params ----------------------------------------

:> test.ini
crudini 2>/dev/null && fail
crudini --met test.ini 2>/dev/null && fail # bad mode
crudini --set 2>/dev/null && fail # no file
crudini --set test.ini  2>/dev/null && fail # no section
crudini --get 2>/dev/null && fail # no file
crudini --get test.ini '' 'name' 'val' 2>/dev/null && fail # value
crudini --get --format=bad test.ini 2>/dev/null && fail # bad format
crudini --del 2>/dev/null && fail # no file
crudini --del test.ini 2>/dev/null && fail # no section
crudini --del test.ini '' 'name' 'val' 2>/dev/null && fail # value
crudini --merge 2>/dev/null && fail # no file
crudini --merge test.ini '' 'name' 2>/dev/null && fail # param
crudini --del test.ini '' 'name' 'val' 2>/dev/null && fail # value
crudini --get --format=ggg test.ini 2>&1 | grep -q 'format not recognized' || fail
crudini --get test.ini 'DEFAULT' missing 2>&1 | grep -q 'Parameter not found' || fail
ok

# --set -------------------------------------------------

:> test.ini
crudini --set test.ini '' name val
printf '%s\n' 'name = val' > good.ini
diff -u test.ini good.ini && ok || fail

:> test.ini
crudini --set test.ini DEFAULT name val
printf '%s\n' '[DEFAULT]' 'name = val' > good.ini
diff -u test.ini good.ini && ok || fail

:> test.ini
crudini --set test.ini nonDEFAULT name val
printf '%s\n' '[nonDEFAULT]' 'name = val' > good.ini
diff -u test.ini good.ini && ok || fail

for bom in '' $'\xef\xbb\xbf'; do
  printf '%s%s\n' "$bom" 'global=val' > test.ini
  crudini --set test.ini '' global valnew
  printf '%s%s\n' "$bom" 'global=valnew' > good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s%s\n' "$bom" 'global=val' > test.ini
  crudini --set test.ini DEFAULT global valnew
  printf '%s%s\n' "$bom" '[DEFAULT]' 'global=valnew' > good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s%s\n' "$bom" '[DEFAULT]' 'global=val' > test.ini
  crudini --set test.ini DEFAULT global valnew
  printf '%s%s\n' "$bom" '[DEFAULT]' 'global=valnew' > good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s%s\n' "$bom" 'global=val' '' '[nonDEFAULT]' 'name=val' > test.ini
  crudini --set test.ini '' global valnew
  printf '%s%s\n' "$bom" 'global=valnew' '' '[nonDEFAULT]' 'name=val' > good.ini
  diff -u test.ini good.ini && ok || fail
done

# do these --sets which test [DEFAULT] handling also with --inplace
for mode in '' '--inplace'; do
# Add '[DEFAULT]' if explicitly specified
  printf '%s\n' 'global=val' '' '[nonDEFAULT]' 'name=val' > test.ini
  crudini $mode --set test.ini DEFAULT global valnew
  printf '%s\n' '[DEFAULT]' 'global=valnew' '' '[nonDEFAULT]' 'name=val' > good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s\n' '[nonDEFAULT1]' 'name=val' '[nonDEFAULT2]' 'name=val' > test.ini
  crudini $mode --set test.ini DEFAULT global val
  printf '%s\n' '[DEFAULT]' 'global = val' '[nonDEFAULT1]' 'name=val' '[nonDEFAULT2]' 'name=val' > good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s\n' '[nonDEFAULT1]' 'name=val' '[nonDEFAULT2]' 'name=val' > test.ini
  crudini $mode --set test.ini '' global val
  printf '%s\n' 'global = val' '[nonDEFAULT1]' 'name=val' '[nonDEFAULT2]' 'name=val' > good.ini
  diff -u test.ini good.ini && ok || fail

  # Ensure '[DEFAULT]' is not duplicated
  printf '%s\n' '[DEFAULT]' > test.ini
  crudini $mode --set test.ini DEFAULT global val
  printf '%s\n' '[DEFAULT]' 'global = val' > good.ini
  diff -u test.ini good.ini && ok || fail

  # Ensure '[DEFAULT]' is not duplicated when trailing space is present
  printf '%s\n' '[DEFAULT]  ' > test.ini
  crudini $mode --set test.ini DEFAULT global val
  printf '%s\n' '[DEFAULT]  ' 'global = val' > good.ini
  diff -u test.ini good.ini && ok || fail

  # Ensure '[DEFAULT]' is not duplicated when a trailing comment is present
  printf '%s\n' '[DEFAULT] #comment' > test.ini
  crudini $mode --set test.ini DEFAULT global val
  printf '%s\n' '[DEFAULT] #comment' 'global = val' > good.ini
  diff -u test.ini good.ini && ok || fail

  # Maintain colon separation
  crudini $mode --set example.ini section1 colon val
  grep -q '^colon:val' example.ini && ok || fail

  # Maintain space separation
  crudini $mode --set example.ini section1 nospace val
  grep -q '^nospace=val' example.ini && ok || fail

  crudini $mode --ini-options= --set example.ini section1 nospace val
  grep -q '^nospace=val' example.ini && ok || fail
done

# value is optional
:> test.ini
crudini --set test.ini '' name
printf '%s\n' 'name = ' > good.ini
diff -u test.ini good.ini && ok || fail

# value is optional
printf '%s\n' 'name=val' > test.ini
crudini --set test.ini '' name
printf '%s\n' 'name=' > good.ini
diff -u test.ini good.ini && ok || fail

# Protect against creating non parseable files (with nested [[]])
:> test.ini
crudini --set test.ini '[section]' name val 2>/dev/null && fail
test -s test.ini && fail
printf '%s\n' '[[section]]' 'name=val' > test.ini
crudini --get test.ini '[section]' name 2>/dev/null && fail
printf '%s\n' '[section]' '[name=val' > test.ini
crudini --get test.ini 'section' '[name' 2>/dev/null && fail
printf '%s\n' '[section]' 'n[ame=val' > test.ini
test $(crudini --get test.ini 'section' 'n[ame') = 'val' && ok || fail

# --existing with file creation
for mode in '' '--inplace'; do
  crudini $mode --set missing.ini '' name val 2>/dev/null && ok || fail
  rm -f missing.ini
  for emode in '' 'file' 'section' 'param'; do
    crudini $mode --existing="$emode" --set missing.ini '' name val \
      2>/dev/null && fail || ok
    test -f missing.ini && fail
  done
  rm -f missing.ini
done

# --existing[=param]
:> test.ini
crudini --set test.ini '' gname val
crudini --set --existing test.ini '' gname val2
crudini --set --existing=inval test.ini '' gname val3 2>/dev/null && fail
crudini --set --existing test.ini '' gname2 val 2>/dev/null && fail
crudini --set test.ini section1 name val
crudini --set --existing test.ini section1 name val2
crudini --set --existing test.ini section1 name2 val 2>/dev/null && fail
printf '%s\n' 'gname = val2' '' '[section1]' 'name = val2' > good.ini
diff -u test.ini good.ini && ok || fail

# --existing=section
:> test.ini
crudini --set test.ini '' gname val
crudini --set --existing='section' test.ini '' gname val2
crudini --set --existing='section' test.ini '' gname2 val 2>/dev/null || fail
crudini --set test.ini section1 name val
crudini --set --existing='section' test.ini section1 name val2
crudini --set --existing='section' test.ini section1 name2 val 2>/dev/null || fail
printf '%s\n' 'gname = val2' 'gname2 = val' \
       '' '[section1]' 'name = val2' 'name2 = val' > good.ini
diff -u test.ini good.ini && ok || fail

# --get -------------------------------------------------

# basic get
test "$(crudini --get example.ini section1 cAps)" = 'not significant' && ok || fail

# unicode get
test "$(crudini --get example.ini non-sh-compat Ăștf8name)" = 'val' && ok || fail

# get sections
crudini --get example.ini > test.ini
printf '%s\n' DEFAULT section1 'empty section' non-sh-compat list > good.ini
diff -u test.ini good.ini && ok || fail

# get implicit default section
crudini --get example.ini '' > test.ini
printf '%s\n' 'global' > good.ini
diff -u test.ini good.ini || fail
crudini --format=ini --get example.ini '' > test.ini
printf '%s\n' '[DEFAULT]' 'global = supported' > good.ini
diff -u test.ini good.ini || fail
ok

# get explicit default section
crudini --get example.ini DEFAULT > test.ini
printf '%s\n' 'global' > good.ini
diff -u test.ini good.ini || fail
crudini --get --format ini example.ini DEFAULT > test.ini
printf '%s\n' '[DEFAULT]' 'global = supported' > good.ini
diff -u test.ini good.ini || fail
ok

# get section1 in ini format
crudini --format=ini --get example.ini section1 > test.ini
diff -u test.ini section1.ini && ok || fail

# get section1 in sh format
crudini --format=sh --get example.ini section1 > test.ini
diff -u test.ini section1.sh && ok || fail
# get all in sh format
crudini --format=sh --get section1.ini > test.ini
diff -u test.ini sections.sh && ok || fail
# get default in sh format
crudini --format=sh --get example.ini '' > test.ini
printf '%s\n' 'global=supported' > good.ini
diff -u test.ini good.ini && ok || fail

# empty DEFAULT is not printed
printf '%s\n' '[DEFAULT]' '#comment' '[section1]' > test.ini
test "$(crudini --get test.ini)" = 'section1' || fail
printf '%s\n' '#comment' '[section1]' > test.ini
test "$(crudini --get test.ini)" = 'section1' || fail
ok

# Ensure we handle comments correctly
printf '%s\n' '[DEFAULT]' '#c1' ';c2' '%inc1' > test.ini
test "$(crudini --get test.ini)" = '' || fail
printf '%s\n' '[section1]' 'remote=1' > test.ini
test "$(crudini --get test.ini 'section1')" = 'remote' || fail
ok

# missing bits
:> test.ini
crudini --get missing.ini 2>/dev/null && fail
test "$(crudini --get test.ini)" = '' || fail
crudini --get test.ini '' || fail
crudini --get test.ini '' 'missing' 2>/dev/null && fail
ok

# --merge -----------------------------------------------

# XXX: An empty default section isn't merged
:> test.ini
printf '%s\n' '[DEFAULT]' '#comment' '[section1]' |
crudini --merge test.ini || fail
printf '%s\n' '[section1]' > good.ini
diff -u test.ini good.ini && ok || fail

:> test.ini
printf '%s\n' '[DEFAULT]' 'name=val' '[section1]' |
crudini --merge test.ini || fail
printf '%s\n' '[DEFAULT]' 'name = val' '[section1]' > good.ini
diff -u test.ini good.ini && ok || fail

:> test.ini
printf '%s\n' 'name=val' |
crudini --merge test.ini || fail
printf '%s\n' 'name = val' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' 'name=val1' > test.ini
printf '%s\n' 'name = val2' |
crudini --merge test.ini || fail
printf '%s\n' 'name=val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' '[DEFAULT]' 'name=val1' > test.ini
printf '%s\n' 'name=val2' |
crudini --merge test.ini || fail
printf '%s\n' '[DEFAULT]' 'name=val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' 'name = val1' > test.ini
printf '%s\n' 'name=val2' |
crudini --merge test.ini '' || fail
printf '%s\n' 'name = val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' '[DEFAULT]' 'name=val1' > test.ini
printf '%s\n' '[DEFAULT]' 'name=val2' |
crudini --merge test.ini || fail
printf '%s\n' '[DEFAULT]' 'name=val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' '[DEFAULT]' 'name=val1' > test.ini
printf '%s\n' '[DEFAULT]' 'name=val2' |
crudini --merge test.ini '' || fail
printf '%s\n' '[DEFAULT]' 'name=val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' '[DEFAULT]' 'name=val1' > test.ini
printf '%s\n' 'name=val2' |
crudini --merge test.ini '' || fail
printf '%s\n' '[DEFAULT]' 'name=val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' 'name=val1' > test.ini
printf '%s\n' 'name=val2' |
crudini --merge test.ini DEFAULT || fail
printf '%s\n' '[DEFAULT]' 'name=val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' 'name=val1' > test.ini
printf '%s\n' 'name=val2' |
crudini --merge test.ini new || fail
printf '%s\n' 'name=val1' '' '[new]' 'name = val2' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' 'name=val1' > test.ini
printf '%s\n' 'name=val2' |
crudini --merge --existing test.ini new 2>/dev/null && fail || ok

printf '%s\n' 'name=val1' > test.ini
printf '%s\n' 'name2=val2' |
crudini --merge --existing test.ini || fail
printf '%s\n' 'name=val1' > good.ini
diff -u test.ini good.ini && ok || fail

printf '%s\n' 'name=val1' '[section1]' 'name=val2' > test.ini
printf '%s\n' 'name=val1a' '[section1]' 'name=val2a' |
crudini --merge --existing test.ini || fail
printf '%s\n' 'name=val1a' '[section1]' 'name=val2a' > good.ini
diff -u test.ini good.ini && ok || fail

# All input sections merged to a specific section
printf '%s\n' 'name=val1' '[section1]' 'name=val2' > test.ini
printf '%s\n' 'name=val2a' '[section2]' 'name2=val' |
crudini --merge test.ini 'section1' || fail
printf '%s\n' 'name=val1' '[section1]' 'name=val2a' 'name2 = val' > good.ini
diff -u test.ini good.ini && ok || fail

# Maintain case for existing parameters
printf '%s\n' '[section]' 'name=val' > test.ini
printf '%s\n' '[section]' 'Name=val' |
crudini --merge test.ini || fail
printf '%s\n' '[section]' 'name=val'> good.ini
diff -u test.ini good.ini && ok || fail

# Honor case for new parameters (spacing not currently honored)
printf '%s\n' '[section]' 'name1=val' > test.ini
printf '%s\n' '[section]' 'Name2=val' |
crudini --merge test.ini || fail
printf '%s\n' '[section]' 'name1=val' 'Name2 = val' > good.ini
diff -u test.ini good.ini && ok || fail

# Note iniparse currently matches sections case insensitively
printf '%s\n' '[section1]' 'name=val1' > test.ini
printf '%s\n' '[Section1]' 'name=val2' |
crudini --merge --existing 2>/dev/null test.ini && fail || ok
printf '%s\n' '[Section1]' 'name=val2' |
crudini --merge test.ini || fail
printf '%s\n' '[section1]' 'name=val1' '' '[Section1]' 'name = val2' > good.ini
diff -u test.ini good.ini && ok || fail

# --del -------------------------------------------------

for sec in '' '[DEFAULT]'; do
  printf '%s\n' $sec 'name = val' > test.ini
  crudini --del test.ini '' noname || fail
  crudini --del --existing test.ini '' noname 2>/dev/null && fail
  crudini --del test.ini '' name || fail
  :> good.ini
  [ "$sec" ] && printf '%s\n' $sec > good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s\n' $sec 'name = val' > test.ini
  crudini --del test.ini 'DEFAULT' noname || fail
  crudini --del --existing test.ini 'DEFAULT' noname 2>/dev/null && fail
  crudini --del test.ini 'DEFAULT' name || fail
  :> good.ini
  [ "$sec" ] && printf '%s\n' $sec > good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s\n' $sec 'name = val' > test.ini
  crudini --del test.ini nosect || fail
  crudini --del --existing=file test.ini nosect || fail
  crudini --del --existing=section test.ini nosect 2>/dev/null && fail
  crudini --del --existing=param test.ini '' noname 2>/dev/null && fail
  crudini --del --existing test.ini nosect 2>/dev/null 2>/dev/null && fail
  crudini --del --existing=param test.ini '' name || fail
  crudini --del test.ini '' || fail
  :> good.ini
  diff -u test.ini good.ini && ok || fail

  printf '%s\n' $sec 'name = val' > test.ini
  crudini --del test.ini nosect || fail
  crudini --del --existing=file test.ini nosect || fail
  crudini --del --existing=section test.ini nosect 2>/dev/null && fail
  crudini --del --existing=param test.ini 'DEFAULT' noname 2>/dev/null && fail
  crudini --del --existing test.ini nosect 2>/dev/null && fail
  crudini --del test.ini 'DEFAULT' || fail
  :> good.ini
  diff -u test.ini good.ini && ok || fail
done

# --del non existing sections/params shouldn't give an error
printf '%s\n' '[section]' 'name = val' > test.ini
crudini --verbose --del test.ini nosect 2>&1 | grep -q ^unchanged || fail
crudini --verbose --del test.ini nosect noname 2>&1 | grep -q ^unchanged || fail
crudini --verbose --del test.ini section noname 2>&1 | grep -q ^unchanged || fail
crudini --verbose --del test.ini section noname 2>&1 | grep -q ^unchanged || fail
crudini --verbose --del --list test.ini section noname val 2>&1 | grep -q ^unchanged || fail
crudini --verbose --del --list test.ini nosect noname val 2>&1 | grep -q ^unchanged || fail
crudini --verbose --del test.ini section 2>&1 | grep -q ^changed || fail
test -s test.ini && fail || ok

# --del non existing file shouldn't create an empty file
crudini --verbose --del missing.ini section 2>&1 | grep -q ^unchanged || fail
crudini --existing --del missing.ini section 2>/dev/null && fail
test -f missing.ini && fail || ok

# --get-lines --------------------------------------------

crudini --get --format=lines example.ini section1 > test.ini || fail
diff -u test.ini section1.lines && ok || fail

crudini --get --format=lines example.ini > test.ini || fail
diff -u test.ini example.lines && ok || fail

# --list -------------------------------------------------

# Add new item to list
crudini --list --set example.ini list list1 v3 || fail
test "$(crudini --get example.ini list list1)" = 'v1, v2, v3' && ok || fail

# Ensure item in list
crudini --list --set example.ini list list1 v3 || fail
test "$(crudini --get example.ini list list1)" = 'v1, v2, v3' && ok || fail

# Delete item from list
crudini --list --del example.ini list list1 v3 || fail
test "$(crudini --get example.ini list list1)" = 'v1, v2' && ok || fail

# Delete non existing item from list
for existing in '' '--existing'; do
  crudini $existing --list --del example.ini list list1 v3 || fail
  test "$(crudini --get example.ini list list1)" = 'v1, v2' && ok || fail
done

# Add new item to list without spacing
#  auto
crudini --list --set example.ini list list2 v3 || fail
test "$(crudini --get example.ini list list2)" = 'v1,v2,v3' && ok || fail
crudini --set example.ini list list2 'v1,v2' || fail
#  explicit
crudini --list --list-sep=, --set example.ini list list2 v3 || fail
test "$(crudini --get example.ini list list2)" = 'v1,v2,v3' && ok || fail


# Delete item from list without spacing
#  auto
crudini --list --del example.ini list list2 v3 || fail
test "$(crudini --get example.ini list list2)" = 'v1,v2' && ok || fail
crudini --set example.ini list list2 'v1,v2,v3' || fail
#  explicit
crudini --list --list-sep=, --del example.ini list list2 v3 || fail
test "$(crudini --get example.ini list list2)" = 'v1,v2' && ok || fail
#  whitespace separated (while maintaining newline separation)
crudini --list --list-sep= --set example.ini list list3 v2 || fail # ignored
crudini --list --list-sep= --set example.ini list list3 v3 || fail
test "$(crudini --get example.ini list list3)" = $'\nv1\nv2\nv3' && ok || fail

# Delete honoring --existing
crudini --list --existing --del example.ini nolist list1 v3 2>/dev/null && fail || ok
crudini --list --existing --del example.ini list nolist1 v3 2>/dev/null && fail || ok

# Support clearing a list by not specifing a value
printf '%s\n' 'empty' 'nonempty = 1' > test.ini
crudini --list --set test.ini '' nonempty 2>/dev/null && ok || fail
test "$(crudini --get test.ini '' nonempty 2>&1)" = '' && ok || fail
crudini --list --set test.ini '' empty 'v1' 2>/dev/null && ok || fail
test "$(crudini --get test.ini '' empty 2>&1)" = 'v1' && ok || fail

# --------------------------------------------------------

# support parsing from stdin
test "$(printf '%s\n' global=1 | crudini --get - '' global)" = 1 && ok || fail

# --verbose
printf '%s\n' '[section]' 'param = value' > test.ini
crudini --verbose --set test.ini section param value 2>&1 | grep -q ^unchanged && ok || fail
crudini --verbose --set test.ini section param valuE 2>&1 | grep -q ^changed && ok || fail
crudini --verbose --del test.ini section param 2>&1 | grep -q ^changed && ok || fail
crudini --verbose --del test.ini section param 2>&1 | grep -q ^unchanged && ok || fail
crudini --verbose --del test.ini section $'multiline\nchanged:' 2>&1 | grep -q ^changed && fail || ok

# ensure leading blank lines maintained with global settings
printf '%s\n' '' 'option=1' > file.conf
printf '%s\n' '' 'option=2' > good.conf
crudini --set file.conf '' option 2 || fail
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# ensure errors diagnosed correctly
crudini --get example.ini 2>err | :
! test -s err && ok || fail  #EPIPE ignored
if test -e /dev/full; then
crudini --get example.ini 2>err >/dev/full
grep -q 'No space left' err && ok || fail
fi

# ensure symlinks handled correctly in file replace mode
printf '%s\n' '[section]' 'param = value' > test.ini
ln -s test.ini ltest.ini
crudini --set ltest.ini section param newvalue || fail
test "$(crudini --get test.ini section param)" = 'newvalue' && ok || fail
crudini --output=ltest.ini --set ltest.ini section param newvalue2 || fail
test "$(crudini --get test.ini section param)" = 'newvalue2' && ok || fail

# Test single token parameters (without equals)
cp ../noequals.ini .
crudini --get noequals.ini >/dev/null && ok || fail
cp noequals.ini noequals_new.ini
printf '%s\n' 'new' 'new_equals = ' >> noequals_new.ini
for param in param{1..3} colon{1..2} new; do
 crudini --set noequals.ini noequals $param || fail
done
crudini --set noequals.ini noequals new_equals '' || fail
diff -u noequals.ini noequals_new.ini && ok || fail

# Test updating of single token parameters
#  Ensure no delimitier added with unspecified value
test "$(crudini --output=- --set noequals.ini noequals param1 \
        | grep param1)" = 'param1' && ok || fail
#  Ensure delimitier added with unspecified value with --list
test "$(crudini --list --output=- --set noequals.ini noequals param1 \
        | grep param1)" = 'param1 = ' && ok || fail
#  Ensure delimitier added with empty value
test "$(crudini --output=- --set noequals.ini noequals param1 '' \
        | grep param1)" = 'param1 = ' && ok || fail
#  Ensure correct spacing with --ini-options=nospace
test "$(crudini --ini-options=nospace --output=- --set noequals.ini \
        noequals param1 value1 \
        | grep param1)" = 'param1=value1' && ok || fail
#  Ensure correct spacing with --ini-options=space
test "$(crudini --ini-options=space --output=- --set noequals.ini \
        noequals param1 value1 \
        | grep param1)" = 'param1 = value1' && ok || fail

# Test can read windows format files
printf '%s\r\n' '' 'empty' 'param=value' > test.ini
test "$(crudini --get test.ini DEFAULT param)" = 'value' && ok || fail
# Test can maintain windows format files
diff -u <(crudini --output=- --ini-options=nospace \
          --set test.ini '' param value) \
        test.ini && ok || fail
printf '%s\r\n' '' 'empty=' > test.ini
diff -u <(crudini --output=- --ini-options=nospace \
          --set test.ini '' empty '') \
        test.ini && ok || fail
printf '%s\r\n' '' 'empty' > test.ini
diff -u <(crudini --output=- --ini-options=nospace \
          --set test.ini '' empty) \
        test.ini && ok || fail

# Test closed stdin
(0<&- crudini --help >/dev/null) && ok || fail

# Test closed stdout
(>&- crudini --get test.ini section param value 2>/dev/null) && fail || ok
(>&- crudini --set - section param value 2>/dev/null) && fail || ok
(>&- crudini --set test.ini section param value) && ok || fail

# Test --ini-options=nospace
diff -u <(crudini --output=- --ini-options=nospace \
          --set nospace-in.ini '' new val) \
        nospace-out.ini && ok || fail
# Test --ini-options=space
diff -u <(crudini --output=- --ini-options=space \
          --set space-out.ini '' new val) \
        space-out.ini && ok || fail
# - Mixed space / nospace not allowed
crudini --get file.conf '' param1 --ini-options=space,nospace \
        2>/dev/null && fail || ok

# Test multi operation
# - Multiple set
printf '%s\n' '' 'param1=?' 'param2=?' > file.conf
printf '%s\n' '' 'param1=1' 'param2=2' > good.conf
crudini --set file.conf '' param1 1 \
        --set file.conf '' param2 2 || fail
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# - Multiple get
printf '%s\n' 'param1=1' 'param2=2' > file.conf
crudini --get file.conf '' param1 \
        --get file.conf '' param2 \
        --format=sh > out.conf || fail
diff -u out.conf file.conf && ok || fail
rm file.conf out.conf

# - Mixed set / del
printf '%s\n' '' 'param1=?' 'param2=?' > file.conf
printf '%s\n' ''            'param2=2' > good.conf
crudini --del file.conf '' param1   \
        --set file.conf '' param2 2 || fail
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# - Mixed set / del with non existing file
printf '%s\n' 'param1 = ' > good.conf
crudini --set file.conf '' param1   \
        --del file.conf '' param3 || fail
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# - Mixed set / get not allowed
crudini --set file.conf '' param1   \
        --get file.conf '' param1  2>/dev/null && fail || ok

# - Multiple files not allowed
printf '%s\n' '[section]' > file1.conf
printf '%s\n' '[section]' > file2.conf
crudini --del file1.conf section --del file2.conf section 2>/dev/null \
  && fail || ok
rm -f file1.conf file2.conf

# - Multiple --merge not allowed
crudini --merge file.conf --merge file.conf < /dev/null 2>/dev/null \
  && fail || ok
rm -f file.conf

# - Interspersed options supported
printf '%s\n' 'param1=1' 'param2=2' > good.conf
crudini --set file.conf '' param1 1  \
        --ini-options nospace \
        --set file.conf '' param2 2 || fail
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# - Conflicting DEFAULT section specs not allowed
crudini --set file.conf '' param1 value \
        --set file.conf DEFAULT param2 value 2>/dev/null \
  && fail || ok
crudini --set file.conf DEFAULT param1 value \
        --set file.conf '' param2 value 2>/dev/null \
  && fail || ok
rm -f file.conf

# Test indentation support
# - --get indented
printf '  %s\n' '[section]' 'param1=1' > file.conf
crudini --ini-options=ignoreindent \
        --get file.conf >/dev/null && ok || fail

# - --set maintaining indented
printf '  %s\n' '[section]' 'param1=a' > good.conf
crudini --ini-options=ignoreindent \
        --set file.conf section param1 a && ok || fail
diff -u good.conf file.conf && ok || fail

# - --set copying indentation
printf '  %s\n' '[section]' 'param1=a' 'param2=b' > good.conf
crudini --ini-options=ignoreindent,nospace \
        --set file.conf section param2 b && ok || fail
diff -u good.conf file.conf && ok || fail

# - --set new indentation for param (on new section)
printf '%s\n' '[section]' '  param1 = a' > good.conf
rm -f file.conf
crudini --ini-options=ignoreindent \
        --set file.conf section '  param1' a && ok || fail
diff -u good.conf file.conf && ok || fail

# - --set copying indentation from param
printf '%s\n' '[section]' '  param1 = a' '  param2 = b' > good.conf
crudini --ini-options=ignoreindent \
        --set file.conf section 'param2' b && ok || fail
diff -u good.conf file.conf && ok || fail

# - --set new indentation for param (on new default section)
printf '%s\n' '  param1 = a' > good.conf
rm -f file.conf
crudini --ini-options=ignoreindent \
        --set file.conf '' '  param1' a && ok || fail
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# Test removal of extraneous empty lines
# implicitly enabled with --del
printf '\n[%s]\n' 1 2 > good.conf
cp good.conf file.conf
for i in 1 2; do crudini --del file.conf $i; crudini --set file.conf $i; done
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# Test addition/removal of empty lines with sectionspace
printf '\n[%s]\n[%s]\n\n[%s]\n\n\n[%s]\n\n' 1 2 3 4 > file.conf
printf '[%s]\n\n[%s]\n\n[%s]\n\n[%s]\n' 1 2 3 4 > good.conf
crudini --set --ini-options=sectionspace file.conf ''
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf

# Test creation of a "default" section
printf '[%s]\n' 'default' > good.conf
crudini --set file.conf default # new
diff -u good.conf file.conf && ok || fail
crudini --set file.conf default # existing
diff -u good.conf file.conf && ok || fail
rm file.conf
crudini --set file.conf default --set file.conf default # double new
diff -u good.conf file.conf && ok || fail
rm file.conf good.conf