def test_translate_twice(): """ Check that the values array is not mutated. """ Translator(MockManager(), get_folder("i18n")) values = ["value"] first = Translator.get("TOKEN_NORMAL", values) second = Translator.get("TOKEN_NORMAL", values) assert first == second assert values == ["value"]
def test_translate_twice_different_values(): """ Check that the values array is taken into account in the LRU cache. """ Translator(get_folder("i18n")) values1 = ["value1"] values2 = ["value2"] first = Translator.get("TOKEN_NORMAL", values=values1) second = Translator.get("TOKEN_NORMAL", values=values2) assert first != second
def test_translate_twice(): """ Check that the values array is not mutated. """ Translator(get_folder("i18n")) values = ["value"] first = Translator.get("TOKEN_NORMAL", values) second = Translator.get("TOKEN_NORMAL", values) assert first == second assert values == ["value"]
def test_load_existing_language(): Translator(MockManager(), get_folder("i18n"), "fr") # Should not fallback on en assert Translator.locale() == "fr" # Test the key fallback assert Translator.get("FALLBACK") == "Fallback" assert Translator.get("LANGUAGE") == "Fran\xe7ais" assert Translator.get("BOUZOUF") == "BOUZOUF"
def test_load_existing_language(): Translator(get_folder("i18n"), "fr") # Should not fallback on en assert Translator.locale() == "fr" # Test the key fallback assert Translator.get("FALLBACK") == "Fallback" assert Translator.get("LANGUAGE") == "Fran\xe7ais" assert Translator.get("BOUZOUF") == "BOUZOUF"
def test_invalid_credentials(manager_factory): """Opening a document without being authenticated is not allowed.""" manager, engine = manager_factory() doc_uid = "0000" Translator(find_resource("i18n"), "en") def has_invalid_credentials(self) -> bool: return True def error_signal() -> None: nonlocal received received = True with manager: direct_edit = manager.direct_edit received = False engine.invalidAuthentication.connect(error_signal) with patch.object(Engine, "has_invalid_credentials", new=has_invalid_credentials): direct_edit._prepare_edit(engine.server_url, doc_uid) assert received
def test_languages(): """Check that all languages are well retrieved.""" folder = Path(__file__).parent.parent.parent / "nxdrive" / "data" / "i18n" Translator(folder) expected = [ ("de", "Deutsch"), ("en", "English"), ("es", "Español"), ("eu", "Euskara"), ("fr", "Français"), ("id", "Bahasa Indonesia"), ("it", "Italiano"), ("ja", "日本語"), ("nl", "Nederlands"), ("pl", "Polski"), ("sv", "Svenska"), ] languages = Translator.languages() assert languages == expected assert len(languages) == len(list(folder.glob("*.json")))
def check_executable_path_error_qt(path: Path, /) -> None: """Display an error using Qt about the app not running from the right path.""" from nxdrive.qt import constants as qt from nxdrive.qt.imports import QApplication, QMessageBox, QPixmap from nxdrive.translator import Translator from nxdrive.utils import find_icon, find_resource app = QApplication([]) app.setQuitOnLastWindowClosed(True) Translator(find_resource("i18n")) content = Translator.get("RUNNING_FROM_WRONG_PATH", values=[str(path), f"{APP_NAME}.app"]) icon = QPixmap(str(find_icon("app_icon.svg"))) msg = QMessageBox() msg.setIconPixmap(icon) msg.setText(content) msg.setWindowTitle(APP_NAME) msg.addButton(Translator.get("QUIT"), qt.AcceptRole) msg.exec_()
def test_load_file(): manager = MockManager() Translator(manager, get_folder("i18n")) # Verify the call to save assert manager.called assert Translator.locale() == "en" manager.called = False # Change to an existing language Translator.set("fr") assert manager.called assert Translator.locale() == "fr" # Test unkown key assert Translator.get("BOUZOUF") == "BOUZOUF" # Test fallback assert Translator.get("FALLBACK") == "Fallback" manager.called = False # Try to switch to bad language with pytest.raises(ValueError): Translator.set("abcd") assert Translator.locale() == "fr" # Nothing should be saved assert not manager.called # Go back to an existing one Translator.set("en") assert manager.called assert Translator.locale() == "en" assert Translator.get("BOUZOUF") == "BOUZOUF" # Change to an existing composed language Translator.set("de-DE") assert Translator.locale() == "de-DE" assert Translator.get("CONNECTION_REFUSED") == "Connection refused"
def test_token(token, result): options = ["First Token", "Another One"] Translator(get_folder("i18n")) assert Translator.get(token, options) == result
def test_load_bad_language(): Translator(get_folder("i18n"), "zzzzzz") # Should fallback on en assert Translator.locale() == "en"
def test_load_file(): Translator(get_folder("i18n")) # Verify the call to save assert Translator.locale() == "en" # Change to an existing language Translator.set("fr") assert Translator.locale() == "fr" # Test unkown key assert Translator.get("BOUZOUF") == "BOUZOUF" # Test fallback assert Translator.get("FALLBACK") == "Fallback" # Try to switch to bad language with pytest.raises(ValueError): Translator.set("abcd") assert Translator.locale() == "fr" # Go back to an existing one Translator.set("en") assert Translator.locale() == "en" assert Translator.get("BOUZOUF") == "BOUZOUF" # Change to an existing composed language Translator.set("de-DE") assert Translator.locale() == "de-DE" assert Translator.get("CONNECTION_REFUSED") == "Connection refused"
def test_non_iniialized(): Translator._singleton = None with pytest.raises(RuntimeError): Translator.get("TEST")
def test_token(token, result): options = ["First Token", "Another One"] Translator(get_folder("i18n")) assert Translator.get(token, values=options) == result
def test_token(token, result): options = ["First Token", "Another One"] Translator(MockManager(), get_folder("i18n")) assert Translator.get(token, options) == result
def test_load_bad_language(): Translator(MockManager(), get_folder("i18n"), "zzzzzz") # Should fallback on en assert Translator.locale() == "en"
def setUpApp(self, server_profile=None, register_roots=True): if Manager._singleton: Manager._singleton = None # Install callback early to be called the last self.addCleanup(self._check_cleanup) self.report_path = os.environ.get("REPORT_PATH") self.tmpdir = os.path.join(os.environ.get("WORKSPACE", ""), "tmp") self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp("-nxdrive-uploads", dir=self.tmpdir) # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp("drive-1", dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp("drive-2", dir=self.tmpdir) # Correct the casing of the temp folders for windows if WINDOWS: import win32api self.local_test_folder_1 = win32api.GetLongPathNameW( self.local_test_folder_1) self.local_test_folder_2 = win32api.GetLongPathNameW( self.local_test_folder_2) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, "Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, "Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, "nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, "nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_2) Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager() self.connected = False i18n_path = self.location + "/resources/i18n" Translator(self.manager_1, i18n_path) Options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager() self.setUpServer(server_profile) self.addCleanup(self.tearDownServer, server_profile) self.addCleanup(self._stop_managers) self.addCleanup(self.generate_report) self._wait_sync = {} self._wait_remote_scan = {} self._remote_changes_count = {} self._no_remote_changes = {} # Set engine_1 and engine_2 attributes self.bind_engine(1, start_engine=False) self.queue_manager_1 = self.engine_1.get_queue_manager() self.bind_engine(2, start_engine=False) self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.local self.local_1 = self.get_local_client(self.sync_root_folder_1) self.local_2 = self.get_local_client(self.sync_root_folder_2) # Document client to be used to create remote test documents # and folders self.remote_document_client_1 = DocRemote( pytest.nuxeo_url, self.user_1, "nxdrive-test-device-1", pytest.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir, ) self.remote_document_client_2 = DocRemote( pytest.nuxeo_url, self.user_2, "nxdrive-test-device-2", pytest.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir, ) # File system client to be used to create remote test documents # and folders self.remote_1 = RemoteBase( pytest.nuxeo_url, self.user_1, "nxdrive-test-device-1", pytest.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir, ) self.remote_2 = RemoteBase( pytest.nuxeo_url, self.user_2, "nxdrive-test-device-2", pytest.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir, ) # Register sync roots if register_roots: self.remote_1.register_as_root(self.workspace_1) self.addCleanup(self._unregister, self.workspace_1) self.remote_2.register_as_root(self.workspace_2) self.addCleanup(self._unregister, self.workspace_2)
def test_non_existing_file(): with pytest.raises(OSError): Translator(MockManager(), get_folder("imagine"))
def test_load_file(): Translator(get_folder("i18n")) # Verify the call to save assert Translator.locale() == "en" # Change to an existing language Translator.set("fr") assert Translator.locale() == "fr" # Test unknown key assert Translator.get("BOUZOUF") == "BOUZOUF" # Test fallback assert Translator.get("FALLBACK") == "Fallback" # Try to switch to bad language with pytest.raises(ValueError): Translator.set("abcd") assert Translator.locale() == "fr" # Go back to an existing one Translator.set("en") assert Translator.locale() == "en" assert Translator.get("BOUZOUF") == "BOUZOUF" # Change to an existing composed language Translator.set("de-DE") assert Translator.locale() == "de-DE" assert Translator.get("CONNECTION_REFUSED") == "Connection refused"
def fatal_error_qt(exc_formatted: str) -> None: """Display a "friendly" dialog box on fatal error using Qt.""" from PyQt5.QtCore import Qt, QUrl from PyQt5.QtGui import QDesktopServices, QIcon from PyQt5.QtWidgets import ( QApplication, QDialog, QDialogButtonBox, QLabel, QTextEdit, QVBoxLayout, ) from nxdrive.translator import Translator from nxdrive.utils import find_icon, find_resource def section(header: str, content: str) -> str: """Format a "section" of information.""" return f"{header}\n```\n{content.strip()}\n```" Translator(find_resource("i18n")) tr = Translator.get app = QApplication([]) app.setQuitOnLastWindowClosed(True) dialog = QDialog() dialog.setWindowTitle(tr("FATAL_ERROR_TITLE", [APP_NAME])) dialog.setWindowIcon(QIcon(str(find_icon("app_icon.svg")))) dialog.resize(800, 600) layout = QVBoxLayout() css = "font-family: monospace; font-size: 12px;" details = [] # Display a little message to apologize info = QLabel(tr("FATAL_ERROR_MSG", [APP_NAME, COMPANY])) info.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) layout.addWidget(info) # Display CLI arguments if sys.argv[1:]: text = tr("FATAL_ERROR_CLI_ARGS") label_cli = QLabel(text) label_cli.setAlignment(Qt.AlignVCenter) cli_args = QTextEdit() cli_args.setStyleSheet(css) cli_args.setReadOnly(True) args = "\n".join(arg for arg in sys.argv[1:]) details.append(section(text, args)) cli_args.setText(args) cli_args.setSizeAdjustPolicy(QTextEdit.AdjustToContents) layout.addWidget(label_cli) layout.addWidget(cli_args) # Display the exception text = tr("FATAL_ERROR_EXCEPTION") label_exc = QLabel(text) label_exc.setAlignment(Qt.AlignVCenter) exception = QTextEdit() exception.setStyleSheet(css) exception.setReadOnly(True) details.append(section(text, exc_formatted)) exception.setText(exc_formatted) layout.addWidget(label_exc) layout.addWidget(exception) # Display last lines from the memory log with suppress(Exception): from nxdrive.report import Report # Last 20th lines raw_lines = Report.export_logs(-20) lines = b"\n".join(raw_lines).decode(errors="replace") if lines: text = tr("FATAL_ERROR_LOGS") label_log = QLabel(text) details.append(section(text, lines)) label_log.setAlignment(Qt.AlignVCenter) layout.addWidget(label_log) logs = QTextEdit() logs.setStyleSheet(css) logs.setReadOnly(True) logs.setLineWrapColumnOrWidth(4096) logs.setLineWrapMode(QTextEdit.FixedPixelWidth) logs.setText(lines) layout.addWidget(logs) def open_update_site() -> None: """Open the update web site.""" with suppress(Exception): QDesktopServices.openUrl(QUrl(Options.update_site_url)) # Buttons buttons = QDialogButtonBox() buttons.setStandardButtons(QDialogButtonBox.Ok) buttons.accepted.connect(dialog.close) update_button = buttons.addButton(tr("FATAL_ERROR_UPDATE_BTN"), QDialogButtonBox.ActionRole) update_button.setToolTip(tr("FATAL_ERROR_UPDATE_TOOLTIP", [APP_NAME])) update_button.clicked.connect(open_update_site) layout.addWidget(buttons) def copy() -> None: """Copy details to the clipboard and change the text of the button. """ osi.cb_set("\n".join(details)) copy_paste.setText(tr("FATAL_ERROR_DETAILS_COPIED")) # "Copy details" button with suppress(Exception): from nxdrive.osi import AbstractOSIntegration osi = AbstractOSIntegration.get(None) copy_paste = buttons.addButton(tr("FATAL_ERROR_DETAILS_COPY"), QDialogButtonBox.ActionRole) copy_paste.clicked.connect(copy) dialog.setLayout(layout) dialog.show() app.exec_()
# resolution of some databases (MySQL...) REMOTE_MODIFICATION_TIME_RESOLUTION = 1.0 # 1s resolution on HFS+ on OSX # ~0.01 sec for NTFS # 0.001 sec for EXT4FS OS_STAT_MTIME_RESOLUTION = 1.0 log = getLogger(__name__) DEFAULT_WAIT_SYNC_TIMEOUT = 10 FILE_CONTENT = b"Lorem ipsum dolor sit amet ..." FAKER = Faker("en_US") LOCATION = normalized_path(__file__).parent.parent Translator(LOCATION / "resources" / "i18n") def nuxeo_url() -> str: """Retrieve the Nuxeo URL.""" return env.NXDRIVE_TEST_NUXEO_URL.split("#")[0] def root_remote(base_folder: str = "/") -> DocRemote: return DocRemote( nuxeo_url(), env.NXDRIVE_TEST_USERNAME, "nxdrive-test-administrator-device", __version__, password=env.NXDRIVE_TEST_PASSWORD, base_folder=base_folder,