oktest 1.0.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c60ec7ce654d0f50f7f2cb6523e2f27f4e843b7e88e37d886a694553805f2d7e
4
- data.tar.gz: 559d192eaa5a321a59db95defbc2e7e4ec271bc8d3b97aeba2b8658a61a1b0d9
3
+ metadata.gz: 5232c4c9a9bf78763791cf182129900a376d1dd619fbf4a21f441ea10c0a7f27
4
+ data.tar.gz: 1d35a5ec4678e1a80624c058a32647cc6013c6a3dc4f87f3590bea2a226ea412
5
5
  SHA512:
6
- metadata.gz: 73e39ea5796c682696127b34bff655870458b509aec487b2420276e8bd892a6a60c82a74895c0be89aa2160a231ef08eb92aff8b5a998ca335e735efbb410487
7
- data.tar.gz: 8795c2227f46c7137d3456fa1040aaff0de3d020748c553439d39c7852a66cd0af7d81150cd26ef4c68907d503501de5c7cd3ec3eb3bfa6bdfe1bf2e4c9d5435
6
+ metadata.gz: 385ddc6a48f39657c38ee43ade9c89677aa686f8e7f55ec90eb9aef7d9dbec795cea55014e48070a22a18b63daea081863a4c6c0afc3c1d24c33316a70fcd149
7
+ data.tar.gz: ea3d7947b5195db3cdfd7a435adbdf0d96edfcfc0a653b67d7a241d4dec3e479c986fe8fc8294427e3c05343681b2308474131a35e5e62b75d1214660e62599e
data/README.md CHANGED
@@ -4,12 +4,13 @@
4
4
 
5
5
  Oktest.rb is a new-style testing library for Ruby.
6
6
 
7
- * `ok {actual} == expected` style assertion.
8
- * **Fixture injection** inspired by dependency injection.
7
+ * `ok {actual} == expected` style [assertion](#assertions).
8
+ * [Fixture injection](#fixture-injection) inspired by dependency injection.
9
9
  * Structured test specifications like RSpec.
10
- * Filtering testcases by pattern or tags.
10
+ * [JSON Matcher](#json-matcher) similar to JSON Schema.
11
+ * [Filtering](#tag-and-filtering) testcases by pattern or tags.
11
12
  * Blue/red color instead of green/red for accesability.
12
- * Small code size (about 2400 lines) and good performance.
13
+ * Small code size (less than 3000 lines) and good performance.
13
14
 
14
15
  ```ruby
15
16
  ### Oktest ### Test::Unit
@@ -54,7 +55,7 @@ Oktest.rb requires Ruby 2.3 or later.
54
55
  * <a href="#install">Install</a>
55
56
  * <a href="#basic-example">Basic Example</a>
56
57
  * <a href="#assertion-failure-and-error">Assertion Failure, and Error</a>
57
- * <a href="#skip-and-todo">Skip, and Todo</a>
58
+ * <a href="#skip-and-todo">Skip and Todo</a>
58
59
  * <a href="#reporting-style">Reporting Style</a>
59
60
  * <a href="#run-all-test-scripts-under-directory">Run All Test Scripts Under Directory</a>
60
61
  * <a href="#tag-and-filtering">Tag and Filtering</a>
@@ -82,6 +83,11 @@ Oktest.rb requires Ruby 2.3 or later.
82
83
  * <a href="#dummy_attrs"><code>dummy_attrs()</code></a>
83
84
  * <a href="#dummy_ivars"><code>dummy_ivars()</code></a>
84
85
  * <a href="#recorder"><code>recorder()</code></a>
86
+ * <a href="#json-matcher">JSON Matcher</a>
87
+ * <a href="#simple-example">Simple Example</a>
88
+ * <a href="#nested-example">Nested Example</a>
89
+ * <a href="#complex-example">Complex Example</a>
90
+ * <a href="#helper-methods-for-json-matcher">Helper Methods for JSON Matcher</a>
85
91
  * <a href="#tips">Tips</a>
86
92
  * <a href="#ok--in-minitest"><code>ok {}</code> in MiniTest</a>
87
93
  * <a href="#testing-rack-application">Testing Rack Application</a>
@@ -165,6 +171,7 @@ Result:
165
171
 
166
172
  ```terminal
167
173
  $ oktest test/example01_test.rb # or: ruby test/example01_test.rb
174
+ ## test/example01_test.rb
168
175
  * Hello
169
176
  * #hello()
170
177
  - [pass] returns greeting message.
@@ -172,6 +179,10 @@ $ oktest test/example01_test.rb # or: ruby test/example01_test.rb
172
179
  ## total:2 (pass:2, fail:0, error:0, skip:0, todo:0) in 0.000s
173
180
  ```
174
181
 
182
+ For accessibility reason, Oktest.rb prints passed test cases in blue color
183
+ instead of green color.
184
+ See https://accessibility.psu.edu/color/colorcoding/#RB for details.
185
+
175
186
 
176
187
  ### Assertion Failure, and Error
177
188
 
@@ -202,19 +213,20 @@ Result:
202
213
 
203
214
  ```terminal
204
215
  $ oktest test/example02_test.rb # or: ruby test/example02_test.rb
216
+ ## test/example02_test.rb
205
217
  * other examples
206
218
  - [Fail] example of assertion failure
207
219
  - [ERROR] example of something error
208
220
  ----------------------------------------------------------------------
209
221
  [Fail] other examples > example of assertion failure
210
- tmp/test/example02_test.rb:9:in `block (3 levels) in <main>'
222
+ test/example02_test.rb:9:in `block (3 levels) in <main>'
211
223
  ok {1+1} == 0 # FAIL
212
224
  $<actual> == $<expected>: failed.
213
225
  $<actual>: 2
214
226
  $<expected>: 0
215
227
  ----------------------------------------------------------------------
216
228
  [ERROR] other examples > example of something error
217
- tmp/test/example02_test.rb:13:in `block (3 levels) in <main>'
229
+ test/example02_test.rb:13:in `block (3 levels) in <main>'
218
230
  x = foobar # NameError
219
231
  NameError: undefined local variable or method `foobar' for #<#<Class:...>:...>
220
232
  ----------------------------------------------------------------------
@@ -222,7 +234,7 @@ NameError: undefined local variable or method `foobar' for #<#<Class:...>:...>
222
234
  ```
223
235
 
224
236
 
225
- ### Skip, and Todo
237
+ ### Skip and Todo
226
238
 
227
239
  test/example03_test.rb:
228
240
 
@@ -256,6 +268,7 @@ Result:
256
268
 
257
269
  ```terminal
258
270
  $ oktest test/example03_test.rb # or: ruby test/example03_test.rb
271
+ ## oktest test/example03_test.rb
259
272
  * other examples
260
273
  - [Skip] example of skip (reason: requires Ruby3)
261
274
  - [TODO] example of todo
@@ -276,6 +289,7 @@ Verbose mode (default):
276
289
 
277
290
  ```terminal
278
291
  $ oktest test/example01_test.rb -s verbose # or -sv
292
+ ## test/example01_test.rb
279
293
  * Hello
280
294
  * #hello()
281
295
  - [pass] returns greeting message.
@@ -287,6 +301,16 @@ Simple mode:
287
301
 
288
302
  ```terminal
289
303
  $ oktest test/example01_test.rb -s simple # or -ss
304
+ ## test/example01_test.rb
305
+ * Hello:
306
+ * #hello(): ..
307
+ ## total:2 (pass:2, fail:0, error:0, skip:0, todo:0) in 0.000s
308
+ ```
309
+
310
+ Compact mode:
311
+
312
+ ```terminal
313
+ $ oktest test/example01_test.rb -s compact # or -sc
290
314
  test/example01_test.rb: ..
291
315
  ## total:2 (pass:2, fail:0, error:0, skip:0, todo:0) in 0.000s
292
316
  ```
@@ -294,7 +318,7 @@ test/example01_test.rb: ..
294
318
  Plain mode:
295
319
 
296
320
  ```terminal
297
- $ oktest test/example01_test.rb -s simple # or -ss
321
+ $ oktest test/example01_test.rb -s plain # or -sp
298
322
  ..
299
323
  ## total:2 (pass:2, fail:0, error:0, skip:0, todo:0) in 0.000s
300
324
  ```
@@ -311,21 +335,23 @@ Quiet mode reports progress only of failed or error test cases (and doesn't
311
335
  report progress of passed ones), so it's output is very compact. This is
312
336
  very useful for large project which contains large number of test cases.
313
337
 
338
+ (Note: `ruby test/example01_test.rb -s <STYLE>` is also available.)
339
+
314
340
 
315
341
  ### Run All Test Scripts Under Directory
316
342
 
317
343
  How to run test scripts under `test` directory:
318
344
 
319
345
  ```terminal
320
- $ ls test
346
+ $ ls test/
321
347
  example01_test.rb example02_test.rb example03_test.rb
322
348
 
323
- $ oktest -s simple test # or: ruby -r oktest -e 'Oktest.main' -- test -s simple
324
- tmp/test/example01_test.rb: ..
325
- tmp/test/example02_test.rb: fE
349
+ $ oktest -s compact test # or: ruby -r oktest -e 'Oktest.main' -- test -s compact
350
+ test/example01_test.rb: ..
351
+ test/example02_test.rb: fE
326
352
  ----------------------------------------------------------------------
327
353
  [Fail] other examples > example of assertion failure
328
- tmp/test/example02_test.rb:9:in `block (3 levels) in <top (required)>'
354
+ test/example02_test.rb:9:in `block (3 levels) in <top (required)>'
329
355
  ok {1+1} == 0 # FAIL
330
356
  -e:1:in `<main>'
331
357
  $<actual> == $<expected>: failed.
@@ -333,12 +359,12 @@ $<actual> == $<expected>: failed.
333
359
  $<expected>: 0
334
360
  ----------------------------------------------------------------------
335
361
  [ERROR] other examples > example of something error
336
- tmp/test/example02_test.rb:13:in `block (3 levels) in <top (required)>'
362
+ test/example02_test.rb:13:in `block (3 levels) in <top (required)>'
337
363
  x = foobar # NameError
338
364
  -e:1:in `<main>'
339
365
  NameError: undefined local variable or method `foobar' for #<#<Class:...>:...>
340
366
  ----------------------------------------------------------------------
341
- tmp/test/example03_test.rb: st
367
+ test/example03_test.rb: st
342
368
  ## total:6 (pass:2, fail:1, error:1, skip:1, todo:1) in 0.000s
343
369
  ```
344
370
 
@@ -348,7 +374,8 @@ Test script filename should be `test_xxx.rb` or `xxx_test.rb`
348
374
 
349
375
  ### Tag and Filtering
350
376
 
351
- `topic()` and `spec()` accepts tag name, for example 'obsolete' or 'experimental'.
377
+ `scope()`, `topic()`, and `spec()` accepts tag name, for example 'obsolete'
378
+ or 'experimental'.
352
379
 
353
380
  test/example04_test.rb:
354
381
 
@@ -388,16 +415,16 @@ Oktest.scope do
388
415
  end
389
416
  ```
390
417
 
391
- It is possible to filter topics and specs by tag name (pattern).
418
+ It is possible to filter topics and specs by tag name or pattern.
419
+ Pattern (!= regular expression) supports `*`, `?`, `[]` and `{}`.
392
420
 
393
421
  ```terminal
394
- $ oktest -F tag=exp tests/ # filter by tag name
395
- $ oktest -F tag='*exp*' tests/ # filter by tag name pattern
396
- $ oktest -F tag='{exp,old}' tests/ # filter by multiple tag names
422
+ $ oktest -F tag=exp test/ # filter by tag name
423
+ $ oktest -F tag='*exp*' test/ # filter by tag name pattern
424
+ $ oktest -F tag='{exp,old}' test/ # filter by multiple tag names
397
425
  ```
398
426
 
399
427
  It is also possible to filter topics or specs by name.
400
- Pattern (!= regular expression) supports `*`, `?`, `[]`, and `{}`.
401
428
 
402
429
  ```terminal
403
430
  $ oktest -F topic='*Integer*' test/ # filter topics by pattern
@@ -407,8 +434,8 @@ $ oktest -F spec='*#[1-3]' test/ # filter specs by pattern
407
434
  If you need negative filter, use `!=` instead of `=`.
408
435
 
409
436
  ```terminal
410
- $ oktest -F spec!='*#5' tests/ # exclude spec 'example #5'
411
- $ oktest -F tag!='{exp,old}' tests/ # exclude tag='exp' or tag='old'
437
+ $ oktest -F spec!='*#5' test/ # exclude spec 'example #5'
438
+ $ oktest -F tag!='{exp,old}' test/ # exclude tag='exp' or tag='old'
412
439
  ```
413
440
 
414
441
 
@@ -452,6 +479,7 @@ Result:
452
479
 
453
480
  ```terminal
454
481
  $ ruby test/example05_test.rb
482
+ ## test/example05_test.rb
455
483
  * Integer
456
484
  * #abs()
457
485
  - When value is negative...
@@ -466,7 +494,7 @@ $ ruby test/example05_test.rb
466
494
 
467
495
  ### Optional: Unary Operators
468
496
 
469
- `topic()` accepts unary `+` operator and `spec()` accepts unary `-` operator.
497
+ `topic()` accepts unary plus (`+`) and `spec()` accepts unary minus (`-`).
470
498
  This makes test scripts more readable.
471
499
 
472
500
  <!--
@@ -500,7 +528,7 @@ end
500
528
 
501
529
  ### Generate Test Code Skeleton
502
530
 
503
- `oktest -G` (or `oktest --generate`) generates test code skeleton from ruby file.
531
+ `oktest --generate` (or `oktest -G`) generates test code skeleton from ruby file.
504
532
  Comment line starting with `#;` is regarded as spec description.
505
533
 
506
534
  hello.rb:
@@ -523,7 +551,7 @@ end
523
551
  Generate test code skeleton:
524
552
 
525
553
  ```terminal
526
- $ oktest -G hello.rb > test/hello_test.rb
554
+ $ oktest --generate hello.rb > test/hello_test.rb
527
555
  ```
528
556
 
529
557
  test/hello_test.rb:
@@ -608,7 +636,7 @@ Oktest.scope do
608
636
  end
609
637
 
610
638
  spec "example" do
611
- s = hello() # call method in spec block
639
+ s = hello() # call it in spec block
612
640
  ok {s} == "Hello!"
613
641
  end
614
642
 
@@ -701,7 +729,7 @@ ok {a}.item(key, e) # alias of `ok {a}.keyval(key, e)`
701
729
  ok {a}.length(e) # fail unless a.length == e
702
730
  ```
703
731
 
704
- It is possible to chan method call of `.attr()` and `.keyval()`.
732
+ It is possible to chain method call of `.attr()` and `.keyval()`.
705
733
 
706
734
  <!--
707
735
  test/example11b_test.rb:
@@ -873,7 +901,7 @@ end
873
901
  ```
874
902
 
875
903
  To catch subclass of error class, invoke `.raise!` instead of `.raise?`.
876
- For example: `ok {pr}.raise!(NameError, /foobar/, subclass: true)`.
904
+ For example: `ok {pr}.raise!(NameError, /foobar/)`.
877
905
 
878
906
  <!--
879
907
  test/example14f_test.rb:
@@ -1017,8 +1045,8 @@ Oktest.scope do
1017
1045
  after { puts "===== Inner: after =====" } # !!!!!
1018
1046
 
1019
1047
  spec "example" do
1020
- ok {1+1} == 2
1021
- end
1048
+ ok {1+1} == 2
1049
+ end
1022
1050
 
1023
1051
  end
1024
1052
 
@@ -1075,7 +1103,7 @@ Oktest.scope do
1075
1103
  end
1076
1104
  ```
1077
1105
 
1078
- * `at_end()` can be called multiple times.
1106
+ * `at_end()` can be called multiple times in a spec.
1079
1107
  * Registered blocks are invoked in reverse order at end of test case.
1080
1108
  * Registered blocks of `at_end()` are invoked prior to block of `after()`.
1081
1109
  * If something error raised in `at_end()`, test script execution will be
@@ -1085,7 +1113,7 @@ end
1085
1113
  ### Named Fixtures
1086
1114
 
1087
1115
  `fixture() { ... }` in topic or scope block defines fixture builder,
1088
- and `fixture()` in scope block returns fixture data.
1116
+ and `fixture()` in spec block returns fixture data.
1089
1117
 
1090
1118
  test/example23_test.rb:
1091
1119
 
@@ -1144,7 +1172,7 @@ Oktest.scope do
1144
1172
  end
1145
1173
  ```
1146
1174
 
1147
- * Fixtures can be defined in block of `topic()` as well as block of `Object.scope()`.
1175
+ * Fixture builders can be defined in `topic()` block as well as `Oktest.scope()` block.
1148
1176
  * If fixture requires clean-up operation, call `at_end()` in `fixture()` block.
1149
1177
 
1150
1178
  ```ruby
@@ -1267,7 +1295,7 @@ Oktest.scope do
1267
1295
  end
1268
1296
  ```
1269
1297
 
1270
- * First argument of `capture_sio()` represents data from `$stdin`.
1298
+ * The first argument of `capture_sio()` represents data from `$stdin`.
1271
1299
  If it is not necessary, you can omit it like `caputre_sio() do ... end`.
1272
1300
  * If you need `$stdin.tty? == true` and `$stdout.tty? == true`,
1273
1301
  call `capture_sio(tty: true) do ... end`.
@@ -1275,7 +1303,7 @@ end
1275
1303
 
1276
1304
  ### `dummy_file()`
1277
1305
 
1278
- `dummy_file()` creates dummy file temporarily.
1306
+ `dummy_file()` creates a dummy file temporarily.
1279
1307
 
1280
1308
  test/example32_test.rb:
1281
1309
 
@@ -1310,12 +1338,12 @@ Oktest.scope do
1310
1338
  end
1311
1339
  ```
1312
1340
 
1313
- * If first argument of `dummy_file()` is nil, then it generates temporary file name automatically.
1341
+ * If the first argument of `dummy_file()` is nil, then it generates temporary file name automatically.
1314
1342
 
1315
1343
 
1316
1344
  ### `dummy_dir()`
1317
1345
 
1318
- `dummy_dir()` creates dummy directory temporarily.
1346
+ `dummy_dir()` creates a dummy directory temporarily.
1319
1347
 
1320
1348
  test/example33_test.rb:
1321
1349
 
@@ -1352,7 +1380,7 @@ Oktest.scope do
1352
1380
  end
1353
1381
  ```
1354
1382
 
1355
- * If first argument of `dummy_dir()` is nil, then it generates temorary directory name automatically.
1383
+ * If the first argument of `dummy_dir()` is nil, then it generates temorary directory name automatically.
1356
1384
 
1357
1385
 
1358
1386
  ### `dummy_values()`
@@ -1519,7 +1547,7 @@ end
1519
1547
 
1520
1548
  ### `recorder()`
1521
1549
 
1522
- `recorder()` returns Benry::Recorder object.
1550
+ `recorder()` returns `Benry::Recorder` object.
1523
1551
  See [Benry::Recorder README](https://github.com/kwatch/benry-ruby/blob/ruby/benry-recorder/README.md)
1524
1552
  for detals.
1525
1553
 
@@ -1584,6 +1612,216 @@ end
1584
1612
 
1585
1613
 
1586
1614
 
1615
+ ## JSON Matcher
1616
+
1617
+ Oktest.rb provides easy way to assert JSON data.
1618
+ This is very convenient feature, but don't abuse it.
1619
+
1620
+
1621
+ ### Simple Example
1622
+
1623
+ <!--
1624
+ test/example41_test.rb:
1625
+ -->
1626
+ ```ruby
1627
+ require 'oktest'
1628
+ require 'set' # !!!!!
1629
+
1630
+ Oktest.scope do
1631
+ topic 'JSON Example' do
1632
+
1633
+ spec "simple example" do
1634
+ actual = {
1635
+ "name": "Alice",
1636
+ "id": 1001,
1637
+ "age": 18,
1638
+ "email": "alice@example.com",
1639
+ "gender": "F",
1640
+ "deleted": false,
1641
+ "tags": ["aaa", "bbb", "ccc"],
1642
+ #"twitter": "@alice",
1643
+ }
1644
+ ## assertion
1645
+ ok {JSON(actual)} === { # requires `JSON()` and `===`
1646
+ "name": "Alice", # scalar value
1647
+ "id": 1000..9999, # range object
1648
+ "age": Integer, # class object
1649
+ "email": /^\w+@example\.com$/, # regexp
1650
+ "gender": Set.new(["M", "F"]), # Set object ("M" or "F")
1651
+ "deleted": Set.new([true, false]), # boolean (true or false)
1652
+ "tags": [/^\w+$/].each, # Enumerator object (!= Array obj)
1653
+ "twitter?": /^@\w+$/, # key 'xxx?' means optional value
1654
+ }
1655
+ end
1656
+
1657
+ end
1658
+ end
1659
+ ```
1660
+
1661
+ (Note: Ruby 2.4 or older doesn't have `Set#===()`, so above code will occur error
1662
+ in Ruby 2.4 or older. Please add the folllowing hack in your test script.)
1663
+
1664
+ ```ruby
1665
+ require 'set'
1666
+ unless Set.instance_methods(false).include?(:===) # for Ruby 2.4 or older
1667
+ class Set; alias === include?; end
1668
+ end
1669
+ ```
1670
+
1671
+ Notice that `Enumerator` has different meaning from `Array` in JSON matcher.
1672
+
1673
+ ```ruby
1674
+ actual = {"tags": ["foo", "bar", "baz"]}
1675
+
1676
+ ## Array
1677
+ ok {JSON(actual)} == {"tags": ["foo", "bar", "baz"]}
1678
+
1679
+ ## Enumerator
1680
+ ok {JSON(actual)} == {"tags": [/^\w+$/].each}
1681
+ ```
1682
+
1683
+
1684
+ ### Nested Example
1685
+
1686
+ <!--
1687
+ test/example42_test.rb:
1688
+ -->
1689
+ ```ruby
1690
+ require 'oktest'
1691
+ require 'set' # !!!!!
1692
+
1693
+ Oktest.scope do
1694
+ topic 'JSON Example' do
1695
+
1696
+ spec "nested example" do
1697
+ actual = {
1698
+ "teams": [
1699
+ {
1700
+ "team": "Section 9",
1701
+ "members": [
1702
+ {"id": 2500, "name": "Aramaki", "gender": "M"},
1703
+ {"id": 2501, "name": "Motoko" , "gender": "F"},
1704
+ {"id": 2502, "name": "Batou" , "gender": "M"},
1705
+ ],
1706
+ "leader": "Aramaki",
1707
+ },
1708
+ {
1709
+ "team": "SOS Brigade",
1710
+ "members": [
1711
+ {"id": 1001, "name": "Haruhi", "gender": "F"},
1712
+ {"id": 1002, "name": "Mikuru", "gender": "F"},
1713
+ {"id": 1003, "name": "Yuki" , "gender": "F"},
1714
+ {"id": 1004, "name": "Itsuki", "gender": "M"},
1715
+ {"id": 1005, "name": "Kyon" , "gender": "M"},
1716
+ ],
1717
+ },
1718
+ ],
1719
+ }
1720
+ ## assertion
1721
+ ok {JSON(actual)} === { # requires `JSON()` and `===`
1722
+ "teams": [
1723
+ {
1724
+ "team": String,
1725
+ "members": [
1726
+ {"id": 1000..9999, "name": String, "gender": Set.new(["M", "F"])}
1727
+ ].each, # Enumerator object (!= Array obj)
1728
+ "leader?": String, # key 'xxx?' means optional value
1729
+ }
1730
+ ].each, # Enumerator object (!= Array obj)
1731
+ }
1732
+ end
1733
+
1734
+ end
1735
+ end
1736
+ ```
1737
+
1738
+
1739
+ ### Complex Example
1740
+
1741
+ * `OR(x, y, z)` matches to `x`, `y`, or `z`.
1742
+ * `AND(x, y, z)` matches to `x`, `y`, and `z`.
1743
+ * Key `"*"` matches to any key of hash object.
1744
+ * `Any()` matches to anything.
1745
+
1746
+ <!--
1747
+ test/example43_test.rb:
1748
+ -->
1749
+ ```ruby
1750
+ require 'oktest'
1751
+ require 'set'
1752
+
1753
+ Oktest.scope do
1754
+ topic 'JSON Example' do
1755
+
1756
+ spec "OR() example" do
1757
+ ok {JSON({"val": "123"})} === {"val": OR(String, Integer)} # OR()
1758
+ ok {JSON({"val": 123 })} === {"val": OR(String, Integer)} # OR()
1759
+ end
1760
+
1761
+ spec "AND() example" do
1762
+ ok {JSON({"val": "123"})} === {"val": AND(String, /^\d+$/)} # AND()
1763
+ ok {JSON({"val": 123 })} === {"val": AND(Integer, 1..1000)} # AND()
1764
+ end
1765
+
1766
+ spec "`*` and `ANY` example" do
1767
+ ok {JSON({"name": "Bob", "age": 20})} === {"*": Any()} # '*' and Any()
1768
+ end
1769
+
1770
+ spec "complex exapmle" do
1771
+ actual = {
1772
+ "item": "awesome item",
1773
+ "colors": ["red", "#cceeff", "green", "#fff"],
1774
+ "memo": "this is awesome.",
1775
+ "url": "https://example.com/awesome",
1776
+ }
1777
+ ## assertion
1778
+ color_names = ["red", "blue", "green", "white", "black"]
1779
+ color_pat = /^\#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/
1780
+ ok {JSON(actual)} === {
1781
+ "colors": [
1782
+ AND(String, OR(Set.new(color_names), color_pat)), # AND() and OR()
1783
+ ].each,
1784
+ "*": Any(), # match to any key (`"*"`) and value (`ANY`)
1785
+ }
1786
+ end
1787
+
1788
+ end
1789
+ end
1790
+ ```
1791
+
1792
+ (Note: `/^\d+$/` implies String value, and `1..100` implies Integer value.)
1793
+
1794
+ ```ruby
1795
+ ## No need to write:
1796
+ ## ok {JSON{...}} === {"val": AND(String, /^\d+$/)}
1797
+ ## ok {JSON{...}} === {"val": AND(Integer, 1..100)}
1798
+ ok {JSON({"val": "A"})} === {"val": /^\d+$/} # implies String value
1799
+ ok {JSON({"val": 99 })} === {"val": 1..100} # implies Integer value
1800
+ ```
1801
+
1802
+
1803
+ ### Helper Methods for JSON Matcher
1804
+
1805
+ Oktest.rb provides some helper methods and objects:
1806
+
1807
+ * `Enum(x, y, z)` is almost same as `Set.new([x, y, z])`.
1808
+ * `Bool()` is same as `Enum(true, false)`.
1809
+ * `Length(3)` matches to length 3, and `Length(1..3)` matches to length 1..3.
1810
+
1811
+ <!--
1812
+ test/example44_test.rb:
1813
+ -->
1814
+ ```ruby
1815
+ actual = {"gender": "M", "deleted": false, "code": "ABCD1234"}
1816
+ ok {JSON(actual)} == {
1817
+ "gender": Enum("M", "F"), # same as Set.new(["M", "F"])
1818
+ "deleted": Bool(), # same as Enum(true, false)
1819
+ "code": Length(6..10), # code length should be 6..10
1820
+ }
1821
+ ```
1822
+
1823
+
1824
+
1587
1825
  ## Tips
1588
1826
 
1589
1827
 
@@ -1592,7 +1830,7 @@ end
1592
1830
  If you want to use `ok {actual} == expected` style assertion in MiniTest,
1593
1831
  install `minitest-ok` gem instead of `otest` gem.
1594
1832
 
1595
- test/example41_test.rb:
1833
+ test/example51_test.rb:
1596
1834
 
1597
1835
  ```ruby
1598
1836
  require 'minitest/spec'
@@ -1615,7 +1853,7 @@ See [minitest-ok README](https://github.com/kwatch/minitest-ok) for details.
1615
1853
 
1616
1854
  `rack-test_app` gem will help you to test Rack application very well.
1617
1855
 
1618
- test/example42_test.rb:
1856
+ test/example52_test.rb:
1619
1857
 
1620
1858
  ```ruby
1621
1859
  require 'rack'
@@ -1648,7 +1886,7 @@ Oktest.scope do
1648
1886
  end
1649
1887
  ```
1650
1888
 
1651
- Defining helper method per topic may help you.
1889
+ Defining helper methods per topic may help you.
1652
1890
 
1653
1891
  ```ruby
1654
1892
  $http = http # !!!!
@@ -1688,7 +1926,7 @@ end
1688
1926
 
1689
1927
  Oktest.rb provides `Traverser` class which implements Visitor pattern.
1690
1928
 
1691
- test/example44_test.rb:
1929
+ test/example54_test.rb:
1692
1930
 
1693
1931
  ```ruby
1694
1932
  require 'oktest'
@@ -1745,8 +1983,8 @@ MyTraverser.new.start()
1745
1983
  Result:
1746
1984
 
1747
1985
  ```terminal
1748
- $ ruby test/example44_test.rb
1749
- # scope: test/example44_test.rb
1986
+ $ ruby test/example54_test.rb
1987
+ # scope: test/example54_test.rb
1750
1988
  + topic: Example Topic
1751
1989
  - spec: sample #1
1752
1990
  - spec: sample #2
@@ -1826,10 +2064,8 @@ ruby run_all.rb | tail -5
1826
2064
 
1827
2065
  ### `--faster` Option
1828
2066
 
1829
- `ok {}` is slightly slower than `assert()` in MiniTest.
1830
- In almost case, you don't need to care about it. But if you are working in
1831
- very larget project and you want to run test scripts as fast as possible,
1832
- try `--faster` option of `oktest` command.
2067
+ If you are working in very larget project and you want to run test scripts
2068
+ as fast as possible, try `--faster` option of `oktest` command.
1833
2069
 
1834
2070
  ```terminal
1835
2071
  $ oktest -s quiet --faster test/ ## only for very large project