openMSX
SymbolManager_test.cc
Go to the documentation of this file.
1#include "catch.hpp"
2#include "SymbolManager.hh"
3
4using namespace openmsx;
5
6TEST_CASE("SymbolManager: isHexDigit")
7{
17 CHECK(SymbolManager::isHexDigit('-') == std::nullopt);
18 CHECK(SymbolManager::isHexDigit('@') == std::nullopt);
19 CHECK(SymbolManager::isHexDigit('G') == std::nullopt);
20 CHECK(SymbolManager::isHexDigit('g') == std::nullopt);
21}
22
23TEST_CASE("SymbolManager: is4DigitHex")
24{
25 CHECK(SymbolManager::is4DigitHex("0000") == 0x0000);
26 CHECK(SymbolManager::is4DigitHex("12ab") == 0x12ab);
27 CHECK(SymbolManager::is4DigitHex("F000") == 0xf000);
28 CHECK(SymbolManager::is4DigitHex("fFfF") == 0xffff);
29 CHECK(SymbolManager::is4DigitHex("") == std::nullopt);
30 CHECK(SymbolManager::is4DigitHex("123") == std::nullopt);
31 CHECK(SymbolManager::is4DigitHex("12345") == std::nullopt);
32 CHECK(SymbolManager::is4DigitHex("abg1") == std::nullopt);
33}
34
35TEST_CASE("SymbolManager: parseValue")
36{
37 SECTION("ok") {
38 // hex
39 CHECK(SymbolManager::parseValue("0xa1") == 0xa1);
40 CHECK(SymbolManager::parseValue("0x1234") == 0x1234);
41 CHECK(SymbolManager::parseValue("0XABCD") == 0xabcd);
42 CHECK(SymbolManager::parseValue("0x00002345") == 0x2345);
43 CHECK(SymbolManager::parseValue("$fedc") == 0xfedc);
44 CHECK(SymbolManager::parseValue("#11aA") == 0x11aa);
45 CHECK(SymbolManager::parseValue("bbffh") == 0xbbff);
46 CHECK(SymbolManager::parseValue("3210H") == 0x3210);
47 CHECK(SymbolManager::parseValue("01234h") == 0x1234);
48 // dec
49 CHECK(SymbolManager::parseValue("123") == 0x007b);
50 CHECK(SymbolManager::parseValue("65535") == 0xffff);
51 CHECK(SymbolManager::parseValue("0020") == 0x0014); // NOT interpreted as octal
52 // bin
53 CHECK(SymbolManager::parseValue("%1100") == 0x000c);
54 CHECK(SymbolManager::parseValue("0b000100100011") == 0x0123);
55 CHECK(SymbolManager::parseValue("0B1111000001011000") == 0xf058);
56 }
57 SECTION("error") {
58 // wrong format
59 CHECK(SymbolManager::parseValue("0xFEDX") == std::nullopt);
60 CHECK(SymbolManager::parseValue("1234a") == std::nullopt);
61 CHECK(SymbolManager::parseValue("-3") == std::nullopt);
62 CHECK(SymbolManager::parseValue("0b00112110") == std::nullopt);
63 // overflow
64 CHECK(SymbolManager::parseValue("0x10000") == std::nullopt);
65 CHECK(SymbolManager::parseValue("65536") == std::nullopt);
66 CHECK(SymbolManager::parseValue("%11110000111100001") == std::nullopt);
67 }
68}
69
70TEST_CASE("SymbolManager: checkLabel")
71{
72 CHECK(SymbolManager::checkLabel("foo", 123) == Symbol("foo", 123));
73 CHECK(SymbolManager::checkLabel("bar:", 234) == Symbol("bar", 234));
74 CHECK(SymbolManager::checkLabel("", 345) == std::nullopt);
75 CHECK(SymbolManager::checkLabel(":", 456) == std::nullopt);
76}
77
78TEST_CASE("SymbolManager: checkLabelAndValue")
79{
80 CHECK(SymbolManager::checkLabelAndValue("foo", "123") == Symbol("foo", 123));
81 CHECK(SymbolManager::checkLabelAndValue("", "123") == std::nullopt);
82 CHECK(SymbolManager::checkLabelAndValue("foo", "bla") == std::nullopt);
83}
84
85TEST_CASE("SymbolManager: detectType")
86{
87 SECTION("on extension") {
88 std::string_view buffer = "content doesn't matter";
89 CHECK(SymbolManager::detectType("symbols.noi", buffer) == SymbolFile::Type::NOICE);
90 CHECK(SymbolManager::detectType("symbols.NOI", buffer) == SymbolFile::Type::NOICE);
91 CHECK(SymbolManager::detectType("symbols.Map", buffer) == SymbolFile::Type::LINKMAP);
92 CHECK(SymbolManager::detectType("symbols.symbol", buffer) == SymbolFile::Type::GENERIC); // pasmo
93 CHECK(SymbolManager::detectType("symbols.publics", buffer) == SymbolFile::Type::GENERIC); // pasmo
94 CHECK(SymbolManager::detectType("symbols.sys", buffer) == SymbolFile::Type::GENERIC); // pasmo
95 CHECK(SymbolManager::detectType("symbols.unknown", buffer) == SymbolFile::Type::GENERIC); // unknown extension
96 }
97 SECTION(".sym extension") {
98 CHECK(SymbolManager::detectType("myfile.sym", "; Symbol table from myfile.asm") == SymbolFile::Type::ASMSX);
99 CHECK(SymbolManager::detectType("myfile.sym", "bla: %equ 123") == SymbolFile::Type::GENERIC);
100 CHECK(SymbolManager::detectType("myfile.sym", "bla: equ 123") == SymbolFile::Type::GENERIC);
101 CHECK(SymbolManager::detectType("myfile.sym", "bla equ #123") == SymbolFile::Type::GENERIC);
102 CHECK(SymbolManager::detectType("myfile.sym", "Sections:") == SymbolFile::Type::VASM);
103 CHECK(SymbolManager::detectType("myfile.sym", "anything else") == SymbolFile::Type::HTC);
104 }
105}
106
107TEST_CASE("SymbolManager: loadLines")
108{
109 auto dummyParser = [](std::span<std::string_view> tokens) -> std::optional<Symbol> {
110 if (tokens.size() == 1) return Symbol{std::string(tokens[0]), 123};
111 return {};
112 };
113
114 SECTION("empty file") {
115 std::string_view buffer;
116 auto file = SymbolManager::loadLines("file.sym", buffer, SymbolFile::Type::GENERIC, dummyParser);
117 CHECK(file.filename == "file.sym");
118 CHECK(file.type == SymbolFile::Type::GENERIC);
119 CHECK(file.symbols.empty());
120 }
121 SECTION("comment + symbol") {
122 std::string_view buffer =
123 "; This is a comment\n"
124 "bla\n" // ok for dummy parser
125 "foo bla\n" // ignored because 2 tokens
126 "bar ; comment on same line\n"; // only 1 token after removing comment
127 auto file = SymbolManager::loadLines("file2.sym", buffer, SymbolFile::Type::NOICE, dummyParser);
128 CHECK(file.filename == "file2.sym");
129 CHECK(file.type == SymbolFile::Type::NOICE);
130 REQUIRE(file.symbols.size() == 2);
131 CHECK(file.symbols[0].name == "bla");
132 CHECK(file.symbols[0].value == 123);
133 CHECK(file.symbols[1].name == "bar");
134 CHECK(file.symbols[1].value == 123);
135 }
136}
137
138TEST_CASE("SymbolManager: loadGeneric")
139{
140 std::string_view buffer =
141 "foo: equ 1\n"
142 "bar equ 2\n"
143 "qux: equ 3 ; comment\n"
144 "; only comment\n"
145 "error equ\n"
146 "error equ 123 extra stuff\n";
147 auto file = SymbolManager::loadGeneric("myfile.sym", buffer);
148 CHECK(file.filename == "myfile.sym");
149 CHECK(file.type == SymbolFile::Type::GENERIC);
150 REQUIRE(file.symbols.size() == 3);
151 CHECK(file.symbols[0].name == "foo");
152 CHECK(file.symbols[0].value == 1);
153 CHECK(file.symbols[1].name == "bar");
154 CHECK(file.symbols[1].value == 2);
155 CHECK(file.symbols[2].name == "qux");
156 CHECK(file.symbols[2].value == 3);
157}
158
159TEST_CASE("SymbolManager: loadNoICE")
160{
161 std::string_view buffer =
162 "def foo 1\n"
163 "def bar 234h ; comment\n"
164 "error def 123\n"
165 "def error 99 extra stuff\n";
166 auto file = SymbolManager::loadNoICE("noice.sym", buffer);
167 CHECK(file.filename == "noice.sym");
168 CHECK(file.type == SymbolFile::Type::NOICE);
169 REQUIRE(file.symbols.size() == 2);
170 CHECK(file.symbols[0].name == "foo");
171 CHECK(file.symbols[0].value == 1);
172 CHECK(file.symbols[1].name == "bar");
173 CHECK(file.symbols[1].value == 0x234);
174}
175
176TEST_CASE("SymbolManager: loadHTC")
177{
178 // TODO verify with an actual HTC file
179 std::string_view buffer =
180 "foo 1234 bla\n"
181 "error 1234\n";
182 auto file = SymbolManager::loadHTC("htc.sym", buffer);
183 CHECK(file.filename == "htc.sym");
184 CHECK(file.type == SymbolFile::Type::HTC);
185 REQUIRE(file.symbols.size() == 1);
186 CHECK(file.symbols[0].name == "foo");
187 CHECK(file.symbols[0].value == 0x1234);
188}
189
190TEST_CASE("SymbolManager: loadVASM")
191{
192 std::string_view buffer =
193 "12AB ignore\n"
194 "Symbols by value:\n"
195 "12AB label\n"
196 "bla foo\n";
197 auto file = SymbolManager::loadVASM("vasm.sym", buffer);
198 CHECK(file.filename == "vasm.sym");
199 CHECK(file.type == SymbolFile::Type::VASM);
200 REQUIRE(file.symbols.size() == 1);
201 CHECK(file.symbols[0].name == "label");
202 CHECK(file.symbols[0].value == 0x12ab);
203}
204
205TEST_CASE("SymbolManager: loadASMSX")
206{
207 std::string_view buffer =
208 "1234h ignore1\n"
209 "12h:3456h ignore2\n"
210 "; global and local\n"
211 "1234h l1\n"
212 "12h:abcdh l2\n";
213 auto file = SymbolManager::loadASMSX("asmsx.sym", buffer);
214 CHECK(file.filename == "asmsx.sym");
215 CHECK(file.type == SymbolFile::Type::ASMSX);
216 REQUIRE(file.symbols.size() == 2);
217 CHECK(file.symbols[0].name == "l1");
218 CHECK(file.symbols[0].value == 0x1234);
219 CHECK(file.symbols[1].name == "l2");
220 CHECK(file.symbols[1].value == 0xabcd);
221}
222
223TEST_CASE("SymbolManager: loadLinkMap")
224{
225 std::string_view buffer =
226 "ignore1 text 2CE7 ignore2 0AEE\n"
227 "ignore3 2E58 ignore3 text 2E4C\n"
228 " Symbol Table\n"
229 "asllmod text 2CE7 asllsub 0AEE\n"
230 "cret 2E58 csv text 2E4C\n"
231 "single text 9876\n"
232 "last 8765\n";
233 auto file = SymbolManager::loadLinkMap("link.map", buffer);
234 CHECK(file.filename == "link.map");
235 CHECK(file.type == SymbolFile::Type::LINKMAP);
236 REQUIRE(file.symbols.size() == 6);
237 CHECK(file.symbols[0].name == "asllmod");
238 CHECK(file.symbols[0].value == 0x2ce7);
239 CHECK(file.symbols[1].name == "asllsub");
240 CHECK(file.symbols[1].value == 0x0aee);
241 CHECK(file.symbols[2].name == "cret");
242 CHECK(file.symbols[2].value == 0x2e58);
243 CHECK(file.symbols[3].name == "csv");
244 CHECK(file.symbols[3].value == 0x2e4c);
245 CHECK(file.symbols[4].name == "single");
246 CHECK(file.symbols[4].value == 0x9876);
247 CHECK(file.symbols[5].name == "last");
248 CHECK(file.symbols[5].value == 0x8765);
249}
TEST_CASE("SymbolManager: isHexDigit")
static std::optional< unsigned > isHexDigit(char c)
static SymbolFile loadLines(std::string_view filename, std::string_view buffer, SymbolFile::Type type, function_ref< std::optional< Symbol >(std::span< std::string_view >)> lineParser)
static SymbolFile::Type detectType(std::string_view filename, std::string_view buffer)
static SymbolFile loadNoICE(std::string_view filename, std::string_view buffer)
static SymbolFile loadHTC(std::string_view filename, std::string_view buffer)
static SymbolFile loadGeneric(std::string_view filename, std::string_view buffer)
static SymbolFile loadVASM(std::string_view filename, std::string_view buffer)
static std::optional< uint16_t > is4DigitHex(std::string_view s)
static std::optional< Symbol > checkLabel(std::string_view label, uint16_t value)
static SymbolFile loadASMSX(std::string_view filename, std::string_view buffer)
static std::optional< uint16_t > parseValue(std::string_view str)
static SymbolFile loadLinkMap(std::string_view filename, std::string_view buffer)
static std::optional< Symbol > checkLabelAndValue(std::string_view label, std::string_view value)
CHECK(m3==m3)
This file implemented 3 utility functions:
Definition Autofire.cc:11