blob: 150200387403e02d1d298e34fc5421b0aa230b14 [file] [log] [blame]
Adam Langleye9ada862015-05-11 17:20:37 -07001/* Copyright (c) 2015, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#ifndef OPENSSL_HEADER_CRYPTO_TEST_FILE_TEST_H
16#define OPENSSL_HEADER_CRYPTO_TEST_FILE_TEST_H
17
David Benjamin4969cc92016-04-22 15:02:23 -040018#include <openssl/base.h>
19
Adam Langleye9ada862015-05-11 17:20:37 -070020#include <stdint.h>
Adam Langleye9ada862015-05-11 17:20:37 -070021
David Benjamin6e899c72016-06-09 18:02:18 -040022OPENSSL_MSVC_PRAGMA(warning(push))
Robert Sloan2424d842017-05-01 07:46:28 -070023OPENSSL_MSVC_PRAGMA(warning(disable : 4702))
Kenny Rootb8494592015-09-25 02:29:14 +000024
Robert Sloan8ff03552017-06-14 12:40:58 -070025#include <functional>
Adam Langleye9ada862015-05-11 17:20:37 -070026#include <map>
Robert Sloan8ff03552017-06-14 12:40:58 -070027#include <memory>
Adam Langleye9ada862015-05-11 17:20:37 -070028#include <set>
Robert Sloan2424d842017-05-01 07:46:28 -070029#include <string>
Adam Langleye9ada862015-05-11 17:20:37 -070030#include <vector>
31
David Benjamin6e899c72016-06-09 18:02:18 -040032OPENSSL_MSVC_PRAGMA(warning(pop))
Adam Langleye9ada862015-05-11 17:20:37 -070033
34// File-based test framework.
35//
36// This module provides a file-based test framework. The file format is based on
Robert Sloan2424d842017-05-01 07:46:28 -070037// that of OpenSSL upstream's evp_test and BoringSSL's aead_test. NIST CAVP test
38// vector files are also supported. Each input file is a sequence of attributes,
39// instructions and blank lines.
Adam Langleye9ada862015-05-11 17:20:37 -070040//
41// Each attribute has the form:
42//
43// Name = Value
44//
Robert Sloan2424d842017-05-01 07:46:28 -070045// Instructions are enclosed in square brackets and may appear without a value:
46//
47// [Name = Value]
48//
49// or
50//
51// [Name]
52//
53// Commas in instruction lines are treated as separate instructions. Thus this:
54//
55// [Name1,Name2]
56//
57// is the same as:
58//
59// [Name1]
60// [Name2]
61//
Adam Langleye9ada862015-05-11 17:20:37 -070062// Either '=' or ':' may be used to delimit the name from the value. Both the
63// name and value have leading and trailing spaces stripped.
64//
Robert Sloan2424d842017-05-01 07:46:28 -070065// Each file contains a number of instruction blocks and test cases.
Adam Langleye9ada862015-05-11 17:20:37 -070066//
Robert Sloan2424d842017-05-01 07:46:28 -070067// An instruction block is a sequence of instructions followed by a blank line.
68// Instructions apply to all test cases following its appearance, until the next
69// instruction block. Instructions are unordered.
70//
71// A test is a sequence of one or more attributes followed by a blank line. For
72// tests that process multiple kinds of test cases, the first attribute is
73// parsed out as the test's type and parameter. Otherwise, attributes are
74// unordered. The first attribute is also included in the set of attributes, so
75// tests which do not dispatch may ignore this mechanism.
76//
77// Additional blank lines and lines beginning with # are ignored.
Adam Langleye9ada862015-05-11 17:20:37 -070078//
79// Functions in this module freely output to |stderr| on failure. Tests should
80// also do so, and it is recommended they include the corresponding test's line
81// number in any output. |PrintLine| does this automatically.
82//
Robert Sloan2424d842017-05-01 07:46:28 -070083// Each attribute in a test and all instructions applying to it must be
84// consumed. When a test completes, if any attributes or insturctions haven't
85// been processed, the framework reports an error.
Adam Langleye9ada862015-05-11 17:20:37 -070086
Robert Sloan8ff03552017-06-14 12:40:58 -070087class FileTest;
88typedef bool (*FileTestFunc)(FileTest *t, void *arg);
Adam Langleye9ada862015-05-11 17:20:37 -070089
90class FileTest {
91 public:
Adam Langleye9ada862015-05-11 17:20:37 -070092 enum ReadResult {
93 kReadSuccess,
94 kReadEOF,
95 kReadError,
96 };
97
Robert Sloan8ff03552017-06-14 12:40:58 -070098 class LineReader {
99 public:
100 virtual ~LineReader() {}
101 virtual ReadResult ReadLine(char *out, size_t len) = 0;
102 };
103
104 struct Options {
105 // path is the path to the input file.
106 const char *path = nullptr;
107 // callback is called for each test. It should get the parameters from this
108 // object and signal any errors by returning false.
109 FileTestFunc callback = nullptr;
110 // arg is an opaque pointer that is passed to |callback|.
111 void *arg = nullptr;
112 // silent suppressed the "PASS" string that is otherwise printed after
113 // successful runs.
114 bool silent = false;
115 // comment_callback is called after each comment in the input is parsed.
116 std::function<void(const std::string&)> comment_callback;
Robert Sloan0db7f542018-01-16 15:48:33 -0800117 // is_kas_test is true if a NIST “KAS” test is being parsed. These tests
118 // are inconsistent with the other NIST files to such a degree that they
119 // need their own boolean.
120 bool is_kas_test = false;
Robert Sloan8ff03552017-06-14 12:40:58 -0700121 };
122
123 explicit FileTest(std::unique_ptr<LineReader> reader,
Robert Sloan0db7f542018-01-16 15:48:33 -0800124 std::function<void(const std::string &)> comment_callback,
125 bool is_kas_test);
Robert Sloan8ff03552017-06-14 12:40:58 -0700126 ~FileTest();
127
Adam Langleye9ada862015-05-11 17:20:37 -0700128 // ReadNext reads the next test from the file. It returns |kReadSuccess| if
129 // successfully reading a test and |kReadEOF| at the end of the file. On
130 // error or if the previous test had unconsumed attributes, it returns
131 // |kReadError|.
132 ReadResult ReadNext();
133
134 // PrintLine is a variant of printf which prepends the line number and appends
135 // a trailing newline.
David Benjamin4969cc92016-04-22 15:02:23 -0400136 void PrintLine(const char *format, ...) OPENSSL_PRINTF_FORMAT_FUNC(2, 3);
Adam Langleye9ada862015-05-11 17:20:37 -0700137
138 unsigned start_line() const { return start_line_; }
139
140 // GetType returns the name of the first attribute of the current test.
141 const std::string &GetType();
142 // GetParameter returns the value of the first attribute of the current test.
143 const std::string &GetParameter();
Adam Langleye9ada862015-05-11 17:20:37 -0700144
145 // HasAttribute returns true if the current test has an attribute named |key|.
146 bool HasAttribute(const std::string &key);
147
148 // GetAttribute looks up the attribute with key |key|. It sets |*out_value| to
149 // the value and returns true if it exists and returns false with an error to
150 // |stderr| otherwise.
151 bool GetAttribute(std::string *out_value, const std::string &key);
152
153 // GetAttributeOrDie looks up the attribute with key |key| and aborts if it is
David Benjamin4969cc92016-04-22 15:02:23 -0400154 // missing. It should only be used after a |HasAttribute| call.
Adam Langleye9ada862015-05-11 17:20:37 -0700155 const std::string &GetAttributeOrDie(const std::string &key);
156
Robert Sloanc6ebb282018-04-30 10:10:26 -0700157 // IgnoreAttribute marks the attribute with key |key| as used.
158 void IgnoreAttribute(const std::string &key) { HasAttribute(key); }
159
Adam Langleye9ada862015-05-11 17:20:37 -0700160 // GetBytes looks up the attribute with key |key| and decodes it as a byte
161 // string. On success, it writes the result to |*out| and returns
162 // true. Otherwise it returns false with an error to |stderr|. The value may
163 // be either a hexadecimal string or a quoted ASCII string. It returns true on
164 // success and returns false with an error to |stderr| on failure.
165 bool GetBytes(std::vector<uint8_t> *out, const std::string &key);
166
Robert Sloan8ff03552017-06-14 12:40:58 -0700167 // AtNewInstructionBlock returns true if the current test was immediately
168 // preceded by an instruction block.
169 bool IsAtNewInstructionBlock() const;
170
Robert Sloan2424d842017-05-01 07:46:28 -0700171 // HasInstruction returns true if the current test has an instruction.
172 bool HasInstruction(const std::string &key);
173
Robert Sloanc6ebb282018-04-30 10:10:26 -0700174 // IgnoreInstruction marks the instruction with key |key| as used.
175 void IgnoreInstruction(const std::string &key) { HasInstruction(key); }
176
Tobias Thierer43be7d22020-03-02 19:23:34 +0000177 // IgnoreAllUnusedInstructions disables checking for unused instructions.
178 void IgnoreAllUnusedInstructions();
179
Robert Sloan2424d842017-05-01 07:46:28 -0700180 // GetInstruction looks up the instruction with key |key|. It sets
181 // |*out_value| to the value (empty string if the instruction has no value)
182 // and returns true if it exists and returns false with an error to |stderr|
183 // otherwise.
184 bool GetInstruction(std::string *out_value, const std::string &key);
185
Robert Sloand9e572d2018-08-27 12:27:00 -0700186 // GetInstructionOrDie looks up the instruction with key |key| and aborts if
187 // it is missing. It should only be used after a |HasInstruction| call.
188 const std::string &GetInstructionOrDie(const std::string &key);
189
Robert Sloanc6ebb282018-04-30 10:10:26 -0700190 // GetInstructionBytes behaves like GetBytes, but looks up the corresponding
191 // instruction.
192 bool GetInstructionBytes(std::vector<uint8_t> *out, const std::string &key);
193
Robert Sloan2424d842017-05-01 07:46:28 -0700194 // CurrentTestToString returns the file content parsed for the current test.
195 // If the current test was preceded by an instruction block, the return test
196 // case is preceded by the instruction block and a single blank line. All
197 // other blank or comment lines are omitted.
198 const std::string &CurrentTestToString() const;
199
Robert Sloan8ff03552017-06-14 12:40:58 -0700200 // InjectInstruction adds a key value pair to the most recently parsed set of
201 // instructions.
202 void InjectInstruction(const std::string &key, const std::string &value);
Robert Sloan2424d842017-05-01 07:46:28 -0700203
Robert Sloan927a4952017-07-03 11:25:09 -0700204 // SkipCurrent passes the current test case. Unused attributes are ignored.
205 void SkipCurrent();
206
Adam Langleye9ada862015-05-11 17:20:37 -0700207 private:
208 void ClearTest();
Robert Sloan2424d842017-05-01 07:46:28 -0700209 void ClearInstructions();
Adam Langleye9ada862015-05-11 17:20:37 -0700210 void OnKeyUsed(const std::string &key);
Robert Sloan2424d842017-05-01 07:46:28 -0700211 void OnInstructionUsed(const std::string &key);
Robert Sloanc6ebb282018-04-30 10:10:26 -0700212 bool ConvertToBytes(std::vector<uint8_t> *out, const std::string &value);
Adam Langleye9ada862015-05-11 17:20:37 -0700213
Robert Sloan8ff03552017-06-14 12:40:58 -0700214 std::unique_ptr<LineReader> reader_;
Adam Langleye9ada862015-05-11 17:20:37 -0700215 // line_ is the number of lines read.
216 unsigned line_ = 0;
217
218 // start_line_ is the line number of the first attribute of the test.
219 unsigned start_line_ = 0;
220 // type_ is the name of the first attribute of the test.
221 std::string type_;
222 // parameter_ is the value of the first attribute.
223 std::string parameter_;
Pete Bentley17486112021-01-20 11:51:47 +0000224 // attribute_count_ maps unsuffixed attribute names to the number of times
225 // they have occurred so far.
226 std::map<std::string, size_t> attribute_count_;
Adam Langleye9ada862015-05-11 17:20:37 -0700227 // attributes_ contains all attributes in the test, including the first.
228 std::map<std::string, std::string> attributes_;
Robert Sloan2424d842017-05-01 07:46:28 -0700229 // instructions_ contains all instructions in scope for the test.
230 std::map<std::string, std::string> instructions_;
Adam Langleye9ada862015-05-11 17:20:37 -0700231
Robert Sloan2424d842017-05-01 07:46:28 -0700232 // unused_attributes_ is the set of attributes that have not been queried.
Adam Langleye9ada862015-05-11 17:20:37 -0700233 std::set<std::string> unused_attributes_;
Adam Langleye9ada862015-05-11 17:20:37 -0700234
Robert Sloan2424d842017-05-01 07:46:28 -0700235 // unused_instructions_ is the set of instructions that have not been queried.
236 std::set<std::string> unused_instructions_;
237
238 std::string current_test_;
239
Robert Sloan8ff03552017-06-14 12:40:58 -0700240 bool is_at_new_instruction_block_ = false;
Robert Sloan0db7f542018-01-16 15:48:33 -0800241 bool seen_non_comment_ = false;
242 bool is_kas_test_ = false;
Robert Sloan8ff03552017-06-14 12:40:58 -0700243
244 // comment_callback_, if set, is a callback function that is called with the
245 // contents of each comment as they are parsed.
246 std::function<void(const std::string&)> comment_callback_;
Robert Sloan2424d842017-05-01 07:46:28 -0700247
248 FileTest(const FileTest &) = delete;
249 FileTest &operator=(const FileTest &) = delete;
Adam Langleye9ada862015-05-11 17:20:37 -0700250};
251
252// FileTestMain runs a file-based test out of |path| and returns an exit code
253// suitable to return out of |main|. |run_test| should return true on pass and
254// false on failure. FileTestMain also implements common handling of the 'Error'
255// attribute. A test with that attribute is expected to fail. The value of the
256// attribute is the reason string of the expected OpenSSL error code.
257//
258// Tests are guaranteed to run serially and may affect global state if need be.
259// It is legal to use "tests" which, for example, import a private key into a
260// list of keys. This may be used to initialize a shared set of keys for many
261// tests. However, if one test fails, the framework will continue to run
262// subsequent tests.
Robert Sloan8ff03552017-06-14 12:40:58 -0700263int FileTestMain(FileTestFunc run_test, void *arg, const char *path);
Adam Langleye9ada862015-05-11 17:20:37 -0700264
Robert Sloan8ff03552017-06-14 12:40:58 -0700265// FileTestMain accepts a larger number of options via a struct.
266int FileTestMain(const FileTest::Options &opts);
267
268// FileTestGTest behaves like FileTestMain, but for GTest. |path| must be the
269// name of a test file embedded in the test binary.
270void FileTestGTest(const char *path, std::function<void(FileTest *)> run_test);
Adam Langleye9ada862015-05-11 17:20:37 -0700271
Robert Sloan8f860b12017-08-28 07:37:06 -0700272#endif // OPENSSL_HEADER_CRYPTO_TEST_FILE_TEST_H