summaryrefslogtreecommitdiffstats
path: root/Help/guide/tutorial/Step3
diff options
context:
space:
mode:
Diffstat (limited to 'Help/guide/tutorial/Step3')
-rw-r--r--Help/guide/tutorial/Step3/CMakeLists.txt20
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt19
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/MathFunctions.cxx19
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h6
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx8
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/mysqrt.h7
-rw-r--r--Help/guide/tutorial/Step3/TutorialConfig.h.in1
-rw-r--r--Help/guide/tutorial/Step3/tutorial.cxx13
8 files changed, 68 insertions, 25 deletions
diff --git a/Help/guide/tutorial/Step3/CMakeLists.txt b/Help/guide/tutorial/Step3/CMakeLists.txt
index 007770a..ac3e9f1 100644
--- a/Help/guide/tutorial/Step3/CMakeLists.txt
+++ b/Help/guide/tutorial/Step3/CMakeLists.txt
@@ -3,13 +3,16 @@ cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Tutorial VERSION 1.0)
+# TODO 4: Replace the following code by:
+# * Creating an interface library called tutorial_compiler_flags
+# Hint: use add_library() with the INTERFACE signature
+# * Add compiler feature cxx_std_11 to tutorial_compiler_flags
+# Hint: Use target_compile_features()
+
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
-# should we use our own math functions
-option(USE_MYMATH "Use tutorial provided math implementation" ON)
-
# configure a header file to pass some of the CMake settings
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)
@@ -17,16 +20,15 @@ configure_file(TutorialConfig.h.in TutorialConfig.h)
# TODO 2: Remove EXTRA_INCLUDES list
# add the MathFunctions library
-if(USE_MYMATH)
- add_subdirectory(MathFunctions)
- list(APPEND EXTRA_LIBS MathFunctions)
- list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
-endif()
+add_subdirectory(MathFunctions)
+list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
# add the executable
add_executable(Tutorial tutorial.cxx)
-target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+# TODO 5: Link Tutorial to tutorial_compiler_flags
+
+target_link_libraries(Tutorial PUBLIC MathFunctions)
# TODO 3: Remove use of EXTRA_INCLUDES
diff --git a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
index 7bf05e0..0ffb9e1 100644
--- a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
@@ -1,5 +1,22 @@
-add_library(MathFunctions mysqrt.cxx)
+add_library(MathFunctions MathFunctions.cxx)
# TODO 1: State that anybody linking to MathFunctions needs to include the
# current source directory, while MathFunctions itself doesn't.
# Hint: Use target_include_directories with the INTERFACE keyword
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+if (USE_MYMATH)
+ target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
+
+ # library that just does sqrt
+ add_library(SqrtLibrary STATIC
+ mysqrt.cxx
+ )
+
+ # TODO 7: Link SqrtLibrary to tutorial_compiler_flags
+
+ target_link_libraries(MathFunctions PUBLIC SqrtLibrary)
+endif()
+
+# TODO 6: Link MathFunctions to tutorial_compiler_flags
diff --git a/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.cxx
new file mode 100644
index 0000000..dc28b4b
--- /dev/null
+++ b/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.cxx
@@ -0,0 +1,19 @@
+#include "MathFunctions.h"
+
+#include <cmath>
+
+#ifdef USE_MYMATH
+# include "mysqrt.h"
+#endif
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+// which square root function should we use?
+#ifdef USE_MYMATH
+ return detail::mysqrt(x);
+#else
+ return std::sqrt(x);
+#endif
+}
+}
diff --git a/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h
index cd36bcc..d5c2f22 100644
--- a/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h
+++ b/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h
@@ -1 +1,5 @@
-double mysqrt(double x);
+#pragma once
+
+namespace mathfunctions {
+double sqrt(double x);
+}
diff --git a/Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx
index abe767d..ba0ac64 100644
--- a/Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx
+++ b/Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx
@@ -1,7 +1,9 @@
-#include <iostream>
+#include "mysqrt.h"
-#include "MathFunctions.h"
+#include <iostream>
+namespace mathfunctions {
+namespace detail {
// a hack square root calculation using simple operations
double mysqrt(double x)
{
@@ -22,3 +24,5 @@ double mysqrt(double x)
}
return result;
}
+}
+}
diff --git a/Help/guide/tutorial/Step3/MathFunctions/mysqrt.h b/Help/guide/tutorial/Step3/MathFunctions/mysqrt.h
new file mode 100644
index 0000000..593d41e
--- /dev/null
+++ b/Help/guide/tutorial/Step3/MathFunctions/mysqrt.h
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace mathfunctions {
+namespace detail {
+double mysqrt(double x);
+}
+}
diff --git a/Help/guide/tutorial/Step3/TutorialConfig.h.in b/Help/guide/tutorial/Step3/TutorialConfig.h.in
index e23f521..7e4d7fa 100644
--- a/Help/guide/tutorial/Step3/TutorialConfig.h.in
+++ b/Help/guide/tutorial/Step3/TutorialConfig.h.in
@@ -1,4 +1,3 @@
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
-#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step3/tutorial.cxx b/Help/guide/tutorial/Step3/tutorial.cxx
index b3c6a4f..a3a2bdc 100644
--- a/Help/guide/tutorial/Step3/tutorial.cxx
+++ b/Help/guide/tutorial/Step3/tutorial.cxx
@@ -3,13 +3,9 @@
#include <iostream>
#include <string>
+#include "MathFunctions.h"
#include "TutorialConfig.h"
-// should we include the MathFunctions header?
-#ifdef USE_MYMATH
-# include "MathFunctions.h"
-#endif
-
int main(int argc, char* argv[])
{
if (argc < 2) {
@@ -23,12 +19,7 @@ int main(int argc, char* argv[])
// convert input to double
const double inputValue = std::stod(argv[1]);
- // which square root function should we use?
-#ifdef USE_MYMATH
- const double outputValue = mysqrt(inputValue);
-#else
- const double outputValue = sqrt(inputValue);
-#endif
+ const double outputValue = mathfunctions::sqrt(inputValue);
std::cout << "The square root of " << inputValue << " is " << outputValue
<< std::endl;
kwd">run_until_complete(tasks.sleep(timeout, loop=loop)) else: run_briefly(loop) return True def run_once(loop): """loop.stop() schedules _raise_stop_error() and run_forever() runs until _raise_stop_error() callback. this wont work if test waits for some IO events, because _raise_stop_error() runs before any of io events callbacks. """ loop.stop() loop.run_forever() class SilentWSGIRequestHandler(WSGIRequestHandler): def get_stderr(self): return io.StringIO() def log_message(self, format, *args): pass class SilentWSGIServer(WSGIServer): def handle_error(self, request, client_address): pass class SSLWSGIServerMixin: def finish_request(self, request, client_address): # The relative location of our test directory (which # contains the ssl key and certificate files) differs # between the stdlib and stand-alone asyncio. # Prefer our own if we can find it. here = os.path.join(os.path.dirname(__file__), '..', 'tests') if not os.path.isdir(here): here = os.path.join(os.path.dirname(os.__file__), 'test', 'test_asyncio') keyfile = os.path.join(here, 'ssl_key.pem') certfile = os.path.join(here, 'ssl_cert.pem') ssock = ssl.wrap_socket(request, keyfile=keyfile, certfile=certfile, server_side=True) try: self.RequestHandlerClass(ssock, client_address, self) ssock.close() except OSError: # maybe socket has been closed by peer pass class SSLWSGIServer(SSLWSGIServerMixin, SilentWSGIServer): pass def _run_test_server(*, address, use_ssl=False, server_cls, server_ssl_cls): def app(environ, start_response): status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) return [b'Test message'] # Run the test WSGI server in a separate thread in order not to # interfere with event handling in the main thread server_class = server_ssl_cls if use_ssl else server_cls httpd = server_class(address, SilentWSGIRequestHandler) httpd.set_app(app) httpd.address = httpd.server_address server_thread = threading.Thread(target=httpd.serve_forever) server_thread.start() try: yield httpd finally: httpd.shutdown() httpd.server_close() server_thread.join() if hasattr(socket, 'AF_UNIX'): class UnixHTTPServer(socketserver.UnixStreamServer, HTTPServer): def server_bind(self): socketserver.UnixStreamServer.server_bind(self) self.server_name = '127.0.0.1' self.server_port = 80 class UnixWSGIServer(UnixHTTPServer, WSGIServer): def server_bind(self): UnixHTTPServer.server_bind(self) self.setup_environ() def get_request(self): request, client_addr = super().get_request() # Code in the stdlib expects that get_request # will return a socket and a tuple (host, port). # However, this isn't true for UNIX sockets, # as the second return value will be a path; # hence we return some fake data sufficient # to get the tests going return request, ('127.0.0.1', '') class SilentUnixWSGIServer(UnixWSGIServer): def handle_error(self, request, client_address): pass class UnixSSLWSGIServer(SSLWSGIServerMixin, SilentUnixWSGIServer): pass def gen_unix_socket_path(): with tempfile.NamedTemporaryFile() as file: return file.name @contextlib.contextmanager def unix_socket_path(): path = gen_unix_socket_path() try: yield path finally: try: os.unlink(path) except OSError: pass @contextlib.contextmanager def run_test_unix_server(*, use_ssl=False): with unix_socket_path() as path: yield from _run_test_server(address=path, use_ssl=use_ssl, server_cls=SilentUnixWSGIServer, server_ssl_cls=UnixSSLWSGIServer) @contextlib.contextmanager def run_test_server(*, host='127.0.0.1', port=0, use_ssl=False): yield from _run_test_server(address=(host, port), use_ssl=use_ssl, server_cls=SilentWSGIServer, server_ssl_cls=SSLWSGIServer) def make_test_protocol(base): dct = {} for name in dir(base): if name.startswith('__') and name.endswith('__'): # skip magic names continue dct[name] = MockCallback(return_value=None) return type('TestProtocol', (base,) + base.__bases__, dct)() class TestSelector(selectors.BaseSelector): def __init__(self): self.keys = {} def register(self, fileobj, events, data=None): key = selectors.SelectorKey(fileobj, 0, events, data) self.keys[fileobj] = key return key def unregister(self, fileobj): return self.keys.pop(fileobj) def select(self, timeout): return [] def get_map(self): return self.keys class TestLoop(base_events.BaseEventLoop): """Loop for unittests. It manages self time directly. If something scheduled to be executed later then on next loop iteration after all ready handlers done generator passed to __init__ is calling. Generator should be like this: def gen(): ... when = yield ... ... = yield time_advance Value returned by yield is absolute time of next scheduled handler. Value passed to yield is time advance to move loop's time forward. """ def __init__(self, gen=None): super().__init__() if gen is None: def gen(): yield self._check_on_close = False else: self._check_on_close = True self._gen = gen() next(self._gen) self._time = 0 self._clock_resolution = 1e-9 self._timers = [] self._selector = TestSelector() self.readers = {} self.writers = {} self.reset_counters() def time(self): return self._time def advance_time(self, advance): """Move test time forward.""" if advance: self._time += advance def close(self): if self._check_on_close: try: self._gen.send(0) except StopIteration: pass else: # pragma: no cover raise AssertionError("Time generator is not finished") def add_reader(self, fd, callback, *args): self.readers[fd] = events.Handle(callback, args, self) def remove_reader(self, fd): self.remove_reader_count[fd] += 1 if fd in self.readers: del self.readers[fd] return True else: return False def assert_reader(self, fd, callback, *args): assert fd in self.readers, 'fd {} is not registered'.format(fd) handle = self.readers[fd] assert handle._callback == callback, '{!r} != {!r}'.format( handle._callback, callback) assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) def add_writer(self, fd, callback, *args): self.writers[fd] = events.Handle(callback, args, self) def remove_writer(self, fd): self.remove_writer_count[fd] += 1 if fd in self.writers: del self.writers[fd] return True else: return False def assert_writer(self, fd, callback, *args): assert fd in self.writers, 'fd {} is not registered'.format(fd) handle = self.writers[fd] assert handle._callback == callback, '{!r} != {!r}'.format( handle._callback, callback) assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) def reset_counters(self): self.remove_reader_count = collections.defaultdict(int) self.remove_writer_count = collections.defaultdict(int) def _run_once(self): super()._run_once() for when in self._timers: advance = self._gen.send(when) self.advance_time(advance) self._timers = [] def call_at(self, when, callback, *args): self._timers.append(when) return super().call_at(when, callback, *args) def _process_events(self, event_list): return def _write_to_self(self): pass def MockCallback(**kwargs): return unittest.mock.Mock(spec=['__call__'], **kwargs) class MockPattern(str): """A regex based str with a fuzzy __eq__. Use this helper with 'mock.assert_called_with', or anywhere where a regex comparison between strings is needed. For instance: mock_call.assert_called_with(MockPattern('spam.*ham')) """ def __eq__(self, other): return bool(re.search(str(self), other, re.S))