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
//! Testing framework for known answer tests.
//!
//! This crate aims to drastically reduce the boilerplate code
//! associated with rust tests, as well as to make known-answer tests easier
//! to write and extend.
//!
//! This framework splits the tests into the test implementation
//! and data, which is stored in .toml files.
//!
//! Under the hood, Kat uses [Serde](https://docs.rs/serde/latest/serde/index.html)
//! and [Toml-rs](https://docs.rs/toml/latest/toml/) to deserialize test data.
//! Both need to be added as dependencies to your crate.
//!
//! ## Getting Started
//! ## Toml file layout
//! The toml file must contain two sections, the **global section**
//! and the **test section** (or sections).
//! ```no_run
//! // In this section global variables are defined.
//! [global]
//! my_global_var = "This is a global variable"
//!
//! // In these sections we define test cases.
//! // Each test owns its own data.
//! // Though every test must have the same
//! // data signature
//! [[test]]
//! id = 0 // int
//! data = "This is data for test 0" // string
//! input = "INPUT" // string
//! expected = "INPUT" // string
//!
//! // Multiple tests can be defined with
//! // consecutive "test" tables
//! [[test]]
//! id = 1 // int
//! data = "This is data for test 1" // string
//! input = "INPUT" // string
//! expected = "INPUT" // string
//! ```
//! If you'd like a comprehensive list of types, that you can
//! include in your toml file, then visit the
//! [Toml Website](https://toml.io/en/v1.0.0)
//!
//! ## Writing the tests
//! Writing the tests is just as straight forward as writing the data.
//! This tutorial will go step by step, in order of definition, and is based
//! on the earlier demonstrated toml file layout.
//!
//! Import the kat crate
//! ---
//! This can be done, either in your test files global namespace
//! (e.g tests/my_test.rs), or in a submodule
//! (e.g tests/my_test.rs::my_submodule).
//! ```no_run
//! // Import Kat
//! use kat::*;
//!```
//! Configure the test file path
//! ---
//! The [kat_cfg] macro configures the filepath of your
//! test file. The path will be interpreted, relative to the
//! workspace root. The file extension can be ommited, since we only support toml.
//! String quotes around the path are not needed, since kat will
//! directly interpolate the path from the macro expression.
//!
//! ```no_run
//! // "WORKSPACE_ROOT/tests/data/my_data.toml"
//! kat_cfg!(tests/data/my_data);
//! ```
//! Global and Test variables
//! ---
//! Now we define the layout for our global and test variables.
//! Define the variables, just like you would in a normal
//! Rust struct.
//!
//! Since Kat, internally uses Serde to deserialize the variables,
//! every type in [global] and [test] must derive Deserialize.
//!
//! More to deserialization of types, in the
//! [Deserializing Types section](./#deserializing-types)
//!
//! The [global] and [test] macros will generate structs
//! which will later be parsed as the test files content.
//! ```no_run
//! // Define global variables
//! global! {
//! // The name of the variable must match
//! // the one defined in your data file.
//! my_global_var: String
//! }
//!
//! // Define our test specific variables.
//! // The same conventions, as in the global!
//! // macro apply.
//! test! {
//! id: usize,
//! data: String,
//! input: String,
//! expected: String,
//! }
//!```
//! Running the tests
//! ---
//! And finally we provide the runner for our tests.
//!
//! Depending on your IDE, you can see
//! a "Run tests" hint (VS Code for example).
//!
//! The tests will be run in the module
//! "YOUR_MODULE::kat_tests", and the main test function
//! is simply called "tests".
//!
//! Inside the [run] macro, you get access to your global and
//! test variables, inside the here named variables `globals` and `test_case`.
//! Both can be named like you would any other variable.
//!
//! On top of that you can execute any statements inside the macro.
//! Though, mutating `globals` and `test_case` is not possible, since
//! they're internally defined as immutable aka read-only.
//!
//! ```no_run
//! // Test Runner
//! run! {
//! // Test Runner
//! //
//! // Note the lambda like invocation syntax.
//! // It's specified in the macro as a match, for
//! // easier readability and familiarity.
//! |globals, test_case| -> {
//!
//! // Now pass the statements you want to run
//!
//! // We can access the global variable.
//! println!("{}", global.my_global_var);
//!
//! // In similar fashion, the test case.
//! println!("{}", test_case.id);
//!
//! // Any statements can be executed
//!
//! // Assertions
//! assert_eq!(test_case.input, test_case.expected);
//!
//! // Function call which is defined somewhere...
//! my_super_expensive_function();
//!
//! // Also from other modules
//! mymod::my_function();
//!
//! // Variables
//! let x = 25;
//!
//! // Macros
//! my_crate::some_macro!();
//! }
//! }
//!
//! ```
//! ### Panics
//! The runner panics, if the test file wasn't found,
//! an IO Error occured (e.g File open unsuccessful),
//! or if toml parsing was erroneous.
//!
//! ---
//! All in all, we end up with a structure like this:
//! ```no_run
//! // Path configuration
//! kat_cfg(...);
//!
//! // Define global variables
//! global! {
//! ...
//! }
//!
//! // Define Test variables
//! test! {
//! ...
//! }
//!
//! // Implement Test Runner
//! run! {
//! |global, test| -> {
//! ...
//! }
//!
//! }
//! ```
//! Runner attributes
//! ---
//! As per usual rust tests, you can annotate the [run] macro with
//! [test attributes](https://doc.rust-lang.org/reference/attributes/testing.html).
//! The initial `#[test]` attribute is already being added for you internally.
//! ```no_run
//! // Ignore tests
//! run! {
//! #[ignore = "not yet implemented"]
//! |global, test| -> {
//! ...
//! }
//! }
//! ```
//! ```no_run
//! // Should panic
//! //
//! // Note, that when running the tests from
//! // the 'run' hint in your IDE, the test will
//! // still be logged as fail. The test will
//! // only accept the panic, when run with
//! // "Cargo test"
//! run! {
//! #[should_panic(expected = "values don't match")]
//! |global, test| -> {
//! assert_eq!(1, 2, "values don't match");
//! }
//! }
//! ```
//! Type Attributes
//! ---
//! Kat supports type attributes for both, types defined
//! in the [global] and [test] macro.
//! ```no_run
//! // Global macro as an example
//! global! {
//! my_type: String,
//!
//! #[my_attribute]
//! my_attributed_type: usize
//! }
//! ```
//! Deserializing Types
//! ---
//! ### Common Types
//! Kat provides the major toml types in its [types] module.
//! However, Kat does not support deserialization of multi-type
//! arrays. For this case it is encouraged to deserialize an array
//! of tables.
//! ```no_run
//! use kat::{types, DeriveTable};
//!
//! // Kat provides a "DeriveTable" attribute,
//! // which actually is an alias for Serde's
//! // Deserialize proc-macro.
//! //
//! // This is how you define a table
//! #[derive(DeriveTable)]
//! struct MyTable {
//! value: types::TomlInt
//! }
//!
//! global! {
//! toml_string: types::TomlString,
//! toml_int: types::TomlInt,
//! toml_float: types::TomlFloat,
//! toml_date: types::TomlDate,
//! toml_bool: types::TomlBool,
//! toml_int_array: types::TomlArray<types::TomlInt>,
//! toml_table: MyTable,
//! }
//!
//! ...
//! ```
//! The test file would look something like this:
//! ```no_run
//! [global]
//! toml_string = "Toml String"
//! toml_int = 10
//! toml_float = 3.1415
//! toml_date = 1979-05-27
//! toml_bool = true
//! toml_int_array = [1, 2, 3, 4, 5]
//! [global.toml_table]
//! value = 22
//!
//! ...
//! ```
//!
//! ### Deserializing Custom Types
//! Since Kat internally deserializes its types with the help of Serde and Toml-rs,
//! primitive types like `String` or `usize` can be parsed directly from toml, without
//! any macro magic, because Serde or Toml-rs provide internal deserialization implementations.
//! So technically you could deserialize custom types with serde attributes.
//! ```no_run
//! // Your custom type
//! struct StringHolder(String);
//! impl From<String> for StringHolder {
//! fn from(s: String) -> Self {
//! Self(s)
//! }
//! }
//!
//! // Generic String deserializer
//! // Deserialize a [T] if it's String constructable
//! fn deserialize_from_string<'de, D, T>(deserializer: D) -> Result<T, D::Error>
//! where
//! D: Deserializer<'de>,
//! T: From<String>
//! {
//! let s = String::deserialize(deserializer)?;
//! Ok(T::from(s))
//! }
//!
//! global! {
//! // Use Serde attribute
//! #[serde(deserialize_with = "deserialize_from_string")]
//! string_holder: StringHolder
//! }
//!
//! ...
//! ```
//! However, this results in a lot of boilerplate code.
//!
//! Luckily, Kat provides you with streamlined ways, in which you can
//! focus on the From implementation, and let Kat handle the code generation:
//! ### Deserialize Custom Types: The Kat way
//! Kat provides macros that generate the code needed to deserialize your value.
//! ```no_run
//! struct StringHolder(String);
//!
//! // Note again the lambda syntax for
//! // familiarity and readability
//! impl_deserialize_from_toml_string!(
//! |s| -> StringHolder {
//! StringHolder(s)
//! }
//! );
//!
//! // Now use it
//! global! {
//! string_holder: StringHolder
//! }
//! ```
//! Inside Toml file
//! ```no_run
//! [global]
//! string_holder = "Hey Ho!"
//!
//! ```
//! Here, `s` denotes the variable name for the passed
//! [TomlString](types::TomlString), you can name it whatever
//! you wish for. Then follows an arrow with the type, the code is
//! to be generated for, here `StringHolder`. And finally the function
//! body.
//!
//! The function body, is essentially the body of the
//! `impl From<TomlString> for StringHolder` implementation,
//! this macro generates. The macro also generates a deserialize
//! implementation.
//!
//! Macros like this exist for all types in the [types] module, but Table and Array.
//! For these two, you will need to call the [impl_deserialize_from_deserializable] macro.
//!
//! The [impl_deserialize_from_deserializable] macro can deserialize a custom type
//! from any type that implements Serde's Deserialize trait.
//! ```no_run
//!
//! #[derive(DeriveTable)]
//! struct MyTable {
//! value: TomlInt
//! }
//!
//! struct MyTableHolder(MyTable)
//!
//! // Denote the input type being typed.
//! // As stated earlier, this macro
//! // generates `impls` from any type that
//! // is deserializable, so it needs the type
//! // annotation.
//! // The rest stays exactly the same.
//! // Note, that MyTableHolder doesn't
//! // have to be a tuple, this still is
//! // simply a From<T> implementation
//! impl_deserialize_from_deserializable!(
//! |table: MyTable| -> MyTableHolder {
//! MyTableHolder(table)
//! }
//! );
//!
//! // From Array
//! struct MyArrayHolder(TomlArray<usize>);
//! impl_deserialize_from_deserializable!(
//! |array: TomlArray<usize>| -> MyArrayHolder {
//! MyArrayHolder(array)
//! }
//! );
//! ```
//! With this macro, it's also possible to chain your custom types.
//! ```no_run
//! // MyArrayHolder from previous example
//!
//! struct HoldsArrayHolder(MyArrayHolder);
//! impl_deserialize_from_deserializable!(
//! |holder: MyArrayHolder| -> HoldsArrayHolder {
//! HoldsArrayHolder(holder)
//! }
//! );
//!
//! ```
//! This is possible, since the macro generated
//! the code for the Deserialize trait for `MyArrayHolder`
//!
//! ## Final Notes
//! It is discouraged to rename the crate, since many macros
//! inside the crate use the `kat::` module namespace
//! in order to directly depent on a type, thus not cluttering the global namespace.
//!
//! On top of that, many exported traits and macros use the `__XXX` prefix.
//! These items typically abstract the code generation away, thus, are private.
//! They should **not** be used directly.
pub use *;
/// Configure the test files location.
/// Defines the global variables inside the test file.
/// Defines the test specific variables inside the test file.
/// Runs the tests.