Skip to content

Commit 362cdbd

Browse files
author
Chris Reed
committed
More semihosting unit tests and minor fixes.
- More complete telnet console unit tests. - Tests for SemihostIOHandler base class. - Test for SemihostAgent constructor's handling of io_handler and console. - Changed InternalSemihostIOHandler.istty() to just assume that the stdio files are ttys. - Fixed InternalSemihostIOHandler.flen(). - Minor improvements to SemihostAgent constuctor, including removing some old unused code. - Added htmlcov coverage html report output dir to gitignore. Signed-off-by: Chris Reed <[email protected]>
1 parent e378a8b commit 362cdbd

File tree

3 files changed

+108
-12
lines changed

3 files changed

+108
-12
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ html
5656

5757
# Coverage
5858
cover
59+
htmlcov
5960

6061
# Common virtualenv environment names
6162
/env

pyOCD/target/semihost.py

+5-11
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ def readc(self):
259259
def istty(self, fd):
260260
if not self._is_valid_fd(fd):
261261
return -1
262-
return int(self.open_files[fd].isatty())
262+
# Just assume that stdio is a terminal and other files aren't.
263+
return int(not fd > STDERR_FD)
263264

264265
def seek(self, fd, pos):
265266
if not self._is_valid_fd(fd):
@@ -275,7 +276,7 @@ def flen(self, fd):
275276
if not self._is_valid_fd(fd):
276277
return -1
277278
try:
278-
info = os.fstat(fd)
279+
info = os.fstat(self.open_files[fd].fileno())
279280
return info.st_size
280281
except OSError as e:
281282
self._errno = e.errno
@@ -453,18 +454,11 @@ class SemihostAgent(object):
453454
def __init__(self, target, io_handler=None, console=None):
454455
self.target = target
455456
self.start_time = time.time()
456-
self.io_handler = io_handler if (io_handler is not None) else SemihostIOHandler()
457+
self.io_handler = io_handler or SemihostIOHandler()
457458
self.io_handler.agent = self
458-
self.console = console if (console is not None) else self.io_handler
459+
self.console = console or self.io_handler
459460
self.console.agent = self
460461

461-
# Go ahead and connect standard I/O
462-
self.open_files = {
463-
STDIN_FD : sys.stdin,
464-
STDOUT_FD : sys.stdout,
465-
STDERR_FD : sys.stderr
466-
}
467-
468462
self.request_map = {
469463
TARGET_SYS_OPEN : self.handle_sys_open,
470464
TARGET_SYS_CLOSE : self.handle_sys_close,

pyOCD/test/test_target/test_semihosting.py

+102-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from pyOCD.target.target import (TARGET_RUNNING, TARGET_HALTED)
2424
from pyOCD.target import semihost
2525
from elapsedtimer import ElapsedTimer
26+
import telnetlib
2627

2728
@pytest.fixture(scope='module', autouse=True)
2829
def debuglog():
@@ -484,11 +485,111 @@ def cleanup():
484485
def semihost_telnet_builder(tgt, semihost_telnet_agent, ramrgn):
485486
return SemihostRequestBuilder(tgt, semihost_telnet_agent, ramrgn)
486487

488+
@pytest.fixture(scope='function')
489+
def telnet_conn(request):
490+
telnet = telnetlib.Telnet('localhost', 4444, 1.0)
491+
def cleanup():
492+
telnet.close()
493+
request.addfinalizer(cleanup)
494+
return telnet
495+
487496
class TestSemihostingTelnet:
488-
def test_start_stop(self, semihost_telnet_builder):
497+
def test_connect(self, semihost_telnet_builder, telnet_conn):
489498
result = semihost_telnet_builder.do_no_args_call(semihost.TARGET_SYS_ERRNO)
490499
assert result == 0
491500

501+
def test_write(self, semihost_telnet_builder, telnet_conn):
502+
result = semihost_telnet_builder.do_write(semihost.STDOUT_FD, 'hello world')
503+
assert result == 0
504+
505+
index, _, text = telnet_conn.expect(['hello world'])
506+
assert index != -1
507+
assert text == 'hello world'
508+
509+
def test_writec(self, semihost_telnet_builder, telnet_conn):
510+
for c in 'xyzzy':
511+
result = semihost_telnet_builder.do_writec(c)
512+
assert result == 0
513+
514+
index, _, text = telnet_conn.expect([c])
515+
assert index != -1
516+
assert text == c
492517

518+
def test_write0(self, semihost_telnet_builder, telnet_conn):
519+
result = semihost_telnet_builder.do_write0('hello world')
520+
assert result == 0
521+
522+
index, _, text = telnet_conn.expect(['hello world'])
523+
assert index != -1
524+
assert text == 'hello world'
525+
526+
def test_read(self, semihost_telnet_builder, telnet_conn):
527+
telnet_conn.write('hello world')
528+
529+
result, data = semihost_telnet_builder.do_read(semihost.STDIN_FD, 11)
530+
assert result == 0
531+
assert data == 'hello world'
532+
533+
def test_readc(self, semihost_telnet_builder, telnet_conn):
534+
telnet_conn.write('xyz')
535+
536+
for c in 'xyz':
537+
rc = semihost_telnet_builder.do_no_args_call(semihost.TARGET_SYS_READC)
538+
assert chr(rc) == c
539+
540+
class TestSemihostAgent:
541+
def test_no_io_handler(self, tgt):
542+
a = semihost.SemihostAgent(tgt, io_handler=None, console=None)
543+
assert type(a.io_handler) is semihost.SemihostIOHandler
544+
assert type(a.console) is semihost.SemihostIOHandler
545+
assert a.console is a.io_handler
546+
547+
def test_only_io_handler(self, tgt):
548+
c = RecordingSemihostIOHandler()
549+
a = semihost.SemihostAgent(tgt, io_handler=c, console=None)
550+
assert a.io_handler is c
551+
assert a.console is c
552+
553+
def test_only_console(self, tgt):
554+
c = RecordingSemihostIOHandler()
555+
a = semihost.SemihostAgent(tgt, io_handler=None, console=c)
556+
assert type(a.io_handler) is semihost.SemihostIOHandler
557+
assert a.console is c
558+
559+
@pytest.fixture
560+
def ioh(tgt):
561+
handler = semihost.SemihostIOHandler()
562+
agent = semihost.SemihostAgent(tgt, io_handler=handler)
563+
return handler, agent
564+
565+
class TestSemihostIOHandlerBase:
566+
@pytest.mark.parametrize(("filename", "mode", "expectedFd"), [
567+
(":tt", 'r', semihost.STDIN_FD),
568+
(":tt", 'w', semihost.STDOUT_FD),
569+
(":tt", 'a', semihost.STDERR_FD),
570+
(":tt", 'r+b', -1),
571+
("somefile", 'r+b', None),
572+
])
573+
def test_std_open(self, tgt, ramrgn, ioh, filename, mode, expectedFd):
574+
handler, agent = ioh
575+
tgt.writeBlockMemoryUnaligned8(ramrgn.start, bytearray(filename) + bytearray('\x00'))
576+
assert handler._std_open(ramrgn.start, len(filename), mode) == (expectedFd, filename)
577+
578+
@pytest.mark.parametrize(("op", "args"), [
579+
('open', (0, 0, 'r')),
580+
('close', (1,)),
581+
('write', (1, 0, 0)),
582+
('read', (1, 0, 0)),
583+
('readc', tuple()),
584+
('istty', (1,)),
585+
('seek', (1, 0)),
586+
('flen', (1,)),
587+
('remove', (0, 0)),
588+
('rename', (0, 0, 0, 0)),
589+
])
590+
def test_unimplemented(self, op, args):
591+
handler = semihost.SemihostIOHandler()
592+
with pytest.raises(NotImplementedError):
593+
handler.__getattribute__(op)(*args)
493594

494595

0 commit comments

Comments
 (0)