If a test has variants, do not add the base test class because that will just cause...
[SquirrelJME.git] / test-writing.mkd
blob73d9cb9db1d278968d7bb802c91c72f745505e42
1 # Test Writing
3 As _SquirrelJME_ is its own virtual machine implementation it uses its own
4 testing system that is different from _JUnit_ or _TestNG_ however it is simple
5 and suits the needs of the project. The main intention of the test framework
6 is to allow for the testing on various virtual machines, since _JUnit_ while
7 it supports _Java SE_ it does not support _Java ME_. So as such there will be
8 some differences as to how tests are written along with their expectations.
10 # Placement of Tests
12 Like standard Java tests, the tests are placed within the standard directory
13 tree as like other _Gradle_ projects:
15  * `module/src/test/java` -- Source code for tests.
16    * `./TestCuteness.java` -- Test source.
17  * `module/src/test/resources` -- Expectations for _SquirrelJME_.
18    * `./TestCuteness.in` -- Test expectations for `TestCuteness`.
20 # Base Test Classes
22 All tests within _SquirrelJME_ extend from one of the base classes that
23 exist depending on what is needed for a test, all of these `abstract` classes
24 are declared in `net.multiphasicapps.tac`:
26  * `TestBiConsumer` -- Takes two arguments, provides no result.
27  * `TestBiFunction` -- Takes two arguments, provides a result.
28  * `TestBoolean` -- Takes no arguments, provides a `boolean`.
29  * `TestConsumer` -- Takes one argument, provides no result.
30  * `TestFunction` -- Takes one argument, provides a result.
31  * `TestInteger` -- Takes an `int` argument.
32  * `TestLong` -- Takes a `long` argument.
33  * `TestRunnable` -- Takes no arguments, provides no result.
34  * `TestSupplier` -- Takes no arguments, provides a result.
36 # Results And Expectations
38 One of the major differences is that _SquirrelJME_'s test expectations are
39 written in an expectations file rather than as something that exists in
40 source code. The manifest itself is in the following format, the keys and
41 values are specified later on in the document. Since there are virtual machine
42 tests and the test framework uses the project's own implementation of the API
43 there can be potential cases where a test may falsely pass because of some
44 event or condition within the project that is erroneous. As such, since the
45 results are elsewhere and static they are for the most part compared via
46 string representation apart from some special conditions.
48 The manifest file is named the same as the test itself and is placed within
49 the same package from within `resources`. The resources are accessed in the
50 same manner as `Class.getResourceAsStream(classBaseName)` and as such
51 is in the specific format:
53 ```manifest
54 result: NoResult
55 thrown: NoExceptionThrown
56 secondary-int--value: int:1234
57 ```
59 The `result` is formed as part of the return value of a method, if there is
60 one. `thrown` is any exception that is thrown from the test method. Any
61 secondary value is set by using `this.secondary(key, value)` from a test, the
62 result is stored for later checking. Secondary keys may be any value however
63 they are dash encoded for special characters.
65 ## Expectation Specifiers
67 The following expectation specifiers are used for various values. Arrays are
68 specified by `[length]` and the values within are split by `,`. Primitive
69 type arrays may have the type followed by `*`, such as `byte*[length]`, if
70 they indicate that the array is of a boxed type, such as `Byte[length]` rather
71 than `byte[length]` in Java.
73 Special specifiers for `result` and `thrown` are these:
75 * `NoResult`
76     * Used only for `result`, specifies the return type is `void`.
77 * `ExceptionThrown`
78     * Used in `result` when an exception is thrown.
79 * `NoExceptionThrown`
80     * No exceptions are thrown from the method.
82 The general value specifiers are:
84  * `true`
85    * True boolean value, which is `Boolean.TRUE`.
86  * `false`
87    * False boolean value, which is `Boolean.FALSE`.
88  * `boolean[<length>]:<arrayValues,>`
89    * Boolean array values, each is encoded as `T` for `true` and `f` for
90      false, and as such `[true, true, false]` encodes as `TTf`.
91  * `string:<encodedString>`
92    * Represents a single string.
93  * `string[<length>]:<asString:,>`
94    * An array of strings, which are encoded accordingly.
95  * `char:<printableNonDigitGlyph|integer>`
96    * A single character.
97    * For printable non-digit ASCII characters this will be the glyph.
98    * Otherwise, it will be an integer of the character code.
99  * `char[<length>]:<asChar:,>`
100    * An array of characters values.
101  * `byte:<integer>`
102    * An integral `byte` value, follows the rules of `Byte.valueOf(String)`.
103  * `byte[<length>]:<asByte:,>`
104    * An array of `byte` values.
105  * `short:<integer>`
106    * An integral `short` value, follows the rules of `Short.valueOf(String)`.
107  * `short[<length>]:<asShort:,>`
108    * An array of `short` values.
109  * `int:<integer>`
110    * An integral `int` value, follows the rules of `Integer.valueOf(String)`.
111  * `int[<length>]:<asInt:,>`
112    * An array of `int` values.
113  * `long:<integer>`
114    * An integral `long` value, follows the rules of `Long.valueOf(String)`.
115  * `long[<length>]:<asLong:,>`
116    * An array of `long` values.
117  * `long-fudge:<asLong>:<absoluteDifference>`
118    * Similar to `long:` except that the value may be within
119      `<absoluteDifference>` using the formula:
120      `expected - diff <= actual <= expected + diff`
121  * `long-ignore-sign:<asLong>`
122    * Similar to `long:` except that the sign bit is ignored.
123  * `throwable:<throwableType>`
124    * An exception that is thrown.
125    * Exceptions in `java.lang` are just the base class name such as
126      `throwable:IllegalArgumentException`.
127    * Otherwise, they are the fully qualified class name such as
128      `throwable:fully.Qualified`.
129  * `other:<encodedString>`
130    * Unknown value type, uses `Object.toString()`.
132 ## String Encoding
134 For any `<encodedString>`, the characters are encoded as the following:
136  * `null` is encoded as `\NULL`.
137  * Double quote (`"`) is encoded as `\"`.
138  * Single quote (`'`) is encoded as `\'`.
139  * Space (` `) is encoded as `\_`.
140  * Newline (`\n`) is encoded as `\n`.
141  * Carriage return (`\r`) is encoded as `\r`.
142  * Tab (`\t`) is encoded as `\t`.
143  * Opening curly brace (`{`) is encoded as `\(`.
144  * Closing curly brace (`}`) is encoded as `\)`.
145  * Delete or `0x7F` is encoded as `\d`.
146  * `0x00` through `0x1F` are encoded as `\0` to `\9` then `A` through `\V`.
147  * Characters at or above 0x7F are encoded as `\@xxxx` with the character
148    hex digit representation.
149  * Otherwise, the ASCII glyph of the character.
151 ## Secondary Key Encoding
153 The following characters map to the specified secondary key encoding:
155  * `-` = `--`
156  * `!` = `-x`
157  * `"` = `-q`
158  * `#` = `-h`
159  * `$` = `-m`
160  * `%` = `-c`
161  * `&` = `-e`
162  * `*` = `-s`
163  * `+` = `-p`
164  * `.` = `-d`
165  * `/` = `-l`
166  * `:` = `-o`
167  * `?` = `-u`
168  * `@` = `-a`
169  * `^` = `-r`
170  * `|` = `-i`
171  * `~` = `-t`
173 # Example
175 An example test with the test expectations:
177 ```java
178 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
179 // ---------------------------------------------------------------------------
180 // SquirrelJME
181 //     Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
182 // ---------------------------------------------------------------------------
183 // SquirrelJME is under the GNU General Public License v3+, or later.
184 // See license.mkd for licensing and copyright information.
185 // ---------------------------------------------------------------------------
187 package lang;
189 import net.multiphasicapps.tac.TestRunnable;
192  * Tests string trim.
194  * @since 2018/12/05
195  */
196 public class TestStringTrim
197         extends TestRunnable
199         /**
200          * {@inheritDoc}
201          * @since 2018/12/05
202          */
203         @Override
204         public void test()
205         {
206                 String cute = "squirrels are cute";
207                 
208                 this.secondary("a", cute.trim());
209                 this.secondary("b", "  \t      squirrels are cute".trim());
210                 this.secondary("c", "squirrels are cute    \t".trim());
211                 this.secondary("d", "       \tsquirrels are cute \t    ".trim());
212                 this.secondary("e", "           ".trim());
213                 this.secondary("f", "           ".trim());
214                 this.secondary("g", cute.trim());
215         }
219 ```manifest
220 result: NoResult
221 thrown: NoExceptionThrown
222 secondary-a: string:squirrels\_are\_cute
223 secondary-b: string:squirrels\_are\_cute
224 secondary-c: string:squirrels\_are\_cute
225 secondary-d: string:squirrels\_are\_cute
226 secondary-e: string:
227 secondary-f: string:
228 secondary-g: string:squirrels\_are\_cute