From e4441df016c7076e6a026191662d984855ee00af Mon Sep 17 00:00:00 2001
From: pompolic <pompolic@special-circumstanc.es>
Date: Tue, 9 Nov 2021 19:45:11 +0100
Subject: [PATCH] Fix breakpoint tests

Steps towards figuring how to run tests spread out across multiple files
---
 gdb-port/tests/run_unittest_main.py       |   3 +
 gdb-port/tests/unit/breakpoints_hammer.py |  10 +-
 gdb-port/tests/unit/breakpoints_pdf.py    |   6 +-
 gdb-port/tests/unit/parser-envs-pdf.py    |   2 +-
 gdb-port/tests/unit/parser_envs_pdf.py    | 128 ++++++++++++++++++++++
 5 files changed, 141 insertions(+), 8 deletions(-)
 create mode 100644 gdb-port/tests/run_unittest_main.py
 create mode 100644 gdb-port/tests/unit/parser_envs_pdf.py

diff --git a/gdb-port/tests/run_unittest_main.py b/gdb-port/tests/run_unittest_main.py
new file mode 100644
index 0000000..decab90
--- /dev/null
+++ b/gdb-port/tests/run_unittest_main.py
@@ -0,0 +1,3 @@
+import unittest
+
+unittest.main(exit=False)
diff --git a/gdb-port/tests/unit/breakpoints_hammer.py b/gdb-port/tests/unit/breakpoints_hammer.py
index fef2eb9..6d51f9d 100644
--- a/gdb-port/tests/unit/breakpoints_hammer.py
+++ b/gdb-port/tests/unit/breakpoints_hammer.py
@@ -3,9 +3,10 @@ import unittest
 
 class PerformLowlevelParseRetBreakpointCreated(unittest.TestCase):
 	def test_breakpoint_is_at_ret(self):
+		breakpoint_loc = int(perform_lowlevel_parse_ret.location.lstrip("*"), 16)
 		arch = gdb.selected_frame().architecture()
-		disassembled_ins = arch.disassemble(perform_lowlevel_parse_ret.location)
-		ins = disassembled_ins['asm'].split(" ")[0]
+		disassembled_ins = arch.disassemble(breakpoint_loc)
+		ins = disassembled_ins[0]['asm'].split(" ")[0]
 
 		self.assertIn(ins, ["ret", "retq"])
 
@@ -14,9 +15,10 @@ class PerformLowlevelParseRetBreakpointCreated(unittest.TestCase):
 
 class HPackratParseRetBreakpointCreated(unittest.TestCase):
 	def test_breakpoint_is_at_ret(self):
+		breakpoint_loc = int(h_packrat_parse_ret.location.lstrip("*"), 16)
 		arch = gdb.selected_frame().architecture()
-		disassembled_ins = arch.disassemble(h_packrat_parse_ret.location)
-		ins = disassembled_ins['asm'].split(" ")[0]
+		disassembled_ins = arch.disassemble(breakpoint_loc)
+		ins = disassembled_ins[0]['asm'].split(" ")[0]
 
 		self.assertIn(ins, ["ret", "retq"])
 
diff --git a/gdb-port/tests/unit/breakpoints_pdf.py b/gdb-port/tests/unit/breakpoints_pdf.py
index 3c0ecb8..b179e62 100644
--- a/gdb-port/tests/unit/breakpoints_pdf.py
+++ b/gdb-port/tests/unit/breakpoints_pdf.py
@@ -3,12 +3,12 @@ import unittest
 # TODO: This actually tests whether the main script set up the breakpoint properly, move to integration
 class InitParserBreakpointCreated(unittest.TestCase):
 	def test_breakpoint_is_at_ret(self):
+		breakpoint_loc = int(init_parser.location.lstrip("*"), 16)
 		arch = gdb.selected_frame().architecture()
-		disassembled_ins = arch.disassemble(init_parser.location)
-		ins = disassembled_ins['asm'].split(" ")[0]
+		disassembled_ins = arch.disassemble(breakpoint_loc)
+		ins = disassembled_ins[0]['asm'].split(" ")[0]
 
 		self.assertIn(ins, ["ret", "retq"])
 
 	def test_not_pending(self):
 		self.assertFalse(init_parser.pending)
-
diff --git a/gdb-port/tests/unit/parser-envs-pdf.py b/gdb-port/tests/unit/parser-envs-pdf.py
index 5cb9f60..13207bd 100644
--- a/gdb-port/tests/unit/parser-envs-pdf.py
+++ b/gdb-port/tests/unit/parser-envs-pdf.py
@@ -126,4 +126,4 @@ class TokenEnvCreation(unittest.TestCase):
 		self.assertIsNotNone(self.parser_env.str_len)
 		self.assertIsInstance(self.parser_env.str_len, int)
 
-unittest.main()
+unittest.main(exit=False)
diff --git a/gdb-port/tests/unit/parser_envs_pdf.py b/gdb-port/tests/unit/parser_envs_pdf.py
new file mode 100644
index 0000000..1c6b973
--- /dev/null
+++ b/gdb-port/tests/unit/parser_envs_pdf.py
@@ -0,0 +1,128 @@
+# These tests use parsers defined in the PDF parser, for expediency
+# There's probably a way to test them in a general manner, but they'd need to be mocked out in process memory
+import unittest
+
+hparser_p_t = gdb.lookup_type("HParser").pointer()
+
+
+class ChoiceEnvCreation(unittest.TestCase):
+	# setup is also  done by parser-name-instrumentation.py and parser-type-instrumentation.py
+	def setUp(self):
+		self.parser_obj = top_level_parse.parsers_by_name("eol")[0]
+		self.parser_env = top_level_parse.parser_decombinator.decompose_parser(self.parser_obj,top_level_parse)
+
+	def test_parser_decombine(self):
+		self.assertIsInstance(self.parser_env, ChoiceEnv)
+
+	def test_member_parsers(self):
+		self.assertIsNotNone(self.parser_env.member_parsers)
+		for p in self.parser_env.member_parsers:
+			self.assertIsInstance(p, Parser)
+
+	def test_member_parsers_name(self):
+		for p in self.parser_env.member_parsers:
+			self.assertIsNotNone(p.name)
+
+	def test_member_parsers_size(self):
+		self.assertEqual(len(self.parser_env.member_parsers),3)
+
+
+# Maybe separate tests for h_left, h_middle, etc.?
+class IgnoreSeqEnvCreation(unittest.TestCase):
+	# setup is also  done by parser-name-instrumentation.py and parser-type-instrumentation.py
+	def setUp(self):
+		self.parser_obj = top_level_parse.parsers_by_name("name")[0]
+		self.parser_env = top_level_parse.parser_decombinator.decompose_parser(self.parser_obj,top_level_parse)
+
+	def test_parser_decombine(self):
+		self.assertIsInstance(self.parser_env, IgnoreSeqEnv)
+
+	def test_member_parsers(self):
+		self.assertIsNotNone(self.parser_env.member_parsers)
+		for p in self.parser_env.member_parsers:
+			self.assertIsInstance(p, Parser)
+
+	def test_member_parsers_name(self):
+		for p in self.parser_env.member_parsers:
+			self.assertIsNotNone(p.name)
+
+	def test_which(self):
+		self.assertIsNotNone(self.parser_env.which)
+		self.assertIsInstance(self.parser_env.which, int)
+
+	def test_member_parsers_size(self):
+		self.assertEqual(len(self.parser_env.member_parsers),2)
+
+
+class ManyEnvCreation(unittest.TestCase):
+	# setup is also  done by parser-name-instrumentation.py and parser-type-instrumentation.py
+	def setUp(self):
+		self.parser_obj = top_level_parse.parsers_by_name("digits")[0]
+		self.parser_env = top_level_parse.parser_decombinator.decompose_parser(self.parser_obj,top_level_parse)
+
+	def test_parser_decombine(self):
+		self.assertIsInstance(self.parser_env, ManyEnv)
+
+	def test_member_parser(self):
+		self.assertIsNotNone(self.parser_env.p)
+		self.assertIsInstance(self.parser_env.p, Parser)
+
+	def test_member_parser_name(self):
+		self.assertIsNotNone(self.parser_env.p.name)
+
+
+# TODO: some parser combinators aren't represented in the H_RULE()s declared
+#class NotEnvCreation(unittest.TestCase):
+	#def setUp(self):
+	#	self.parser_obj = top_level_parse.parsers_by_name("")[0]
+	#	self.parser_env = top_level_parse.parser_decombinator.decompose_parser(self.parser_obj,top_level_parse)
+
+	#def test_parser_decombine(self):
+	#	self.assertIsInstance(self.parser_env, NotEnv)
+
+	#def test_member_parser(self):
+		# Member parser gets extracted from memory
+	#	self.assertIsNotNone(self.parser_env.member_parser)
+		# Parser gets named on creation
+	#	self.assertIsNotNone(self.parser_env.member_parser.name)
+
+
+class SequenceEnvCreation(unittest.TestCase):
+	# setup is also  done by parser-name-instrumentation.py and parser-type-instrumentation.py
+	def setUp(self):
+		self.parser_obj = top_level_parse.parsers_by_name("comment")[0]
+		self.parser_env = top_level_parse.parser_decombinator.decompose_parser(self.parser_obj,top_level_parse)
+
+	def test_parser_decombine(self):
+		self.assertIsInstance(self.parser_env, SequenceEnv)
+
+	def test_member_parsers(self):
+		self.assertIsNotNone(self.parser_env.member_parsers)
+		for p in self.parser_env.member_parsers:
+			self.assertIsInstance(p, Parser)
+
+	def test_member_parsers_name(self):
+		for p in self.parser_env.member_parsers:
+			self.assertIsNotNone(p.name)
+
+	def test_member_parsers_size(self):
+		self.assertEqual(len(self.parser_env.member_parsers),3)
+
+class TokenEnvCreation(unittest.TestCase):
+	def setUp(self):
+		self.parser_obj = top_level_parse.parsers_by_name("null")[0]
+		self.parser_env = top_level_parse.parser_decombinator.decompose_parser(self.parser_obj,top_level_parse)
+		self.token_type = gdb.lookup_type("uint8_t").pointer()
+
+	def test_parser_decombine(self):
+		self.assertIsInstance(self.parser_env, TokenEnv)
+
+	def test_token(self):
+		self.assertIsNotNone(self.parser_env.token)
+		self.assertIsInstance(self.parser_env.token, gdb.Value)
+		self.assertEqual(self.parser_env.token.type, self.token_type) # For gdb.Type objects, == checks for equivalence, and the "is" operator won't work
+
+	def test_str_len(self):
+		self.assertIsNotNone(self.parser_env.str_len)
+		self.assertIsInstance(self.parser_env.str_len, int)
+
-- 
GitLab