Source code for ramble.test.edit_file_validation

# Copyright 2022-2026 The Ramble Authors
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.

import pytest

import ramble.language.language_helpers
from ramble.language.shared_language import edit_file


[docs] class MockApp: def __init__(self): self.name = "mock_app" self.origin_type = "application" self.executables = {} self.custom_edit_functions = {}
[docs] @pytest.fixture def mock_app(): return MockApp()
[docs] def test_edit_file_valid_function(mock_app): def my_custom_edit(content): return content.replace("a", "b") # The directive is usually used as a decorator on the class, # but here we call the returned function directly. edit_func = edit_file("my_edit", "/path/f", function=my_custom_edit) edit_func(mock_app) assert "my_edit" in mock_app.custom_edit_functions source = mock_app.custom_edit_functions["my_edit"] assert "def custom_edit_my_edit_my_custom_edit(content):" in source assert "return my_custom_edit(content)" in source template = mock_app.executables[frozenset()]["my_edit"].template[0] assert "--function custom_edit_my_edit_my_custom_edit" in template
[docs] def test_edit_file_invalid_lambda(mock_app): with pytest.raises( ramble.language.language_helpers.DirectiveError, match="Directive 'my_edit' in application 'mock_app' requires a named top-level " "function, not a lambda or a method", ): edit_func = edit_file("my_edit", "/path/f", function=lambda c: c) edit_func(mock_app)
[docs] def test_edit_file_invalid_method(mock_app): class SomeClass: def my_method(self, content): return content with pytest.raises( ramble.language.language_helpers.DirectiveError, match="Directive 'my_edit' in application 'mock_app' requires a named top-level " "function, not a lambda or a method", ): edit_func = edit_file("my_edit", "/path/f", function=SomeClass().my_method) edit_func(mock_app)
[docs] def test_edit_file_invalid_signature(mock_app): def too_many_args(content, extra): return content with pytest.raises( ramble.language.language_helpers.DirectiveError, match="Directive 'my_edit' in application 'mock_app' requires a function that " "accepts exactly one argument", ): edit_func = edit_file("my_edit", "/path/f", function=too_many_args) edit_func(mock_app)
[docs] def test_edit_file_missing_return(mock_app): def no_return(content): print(content) with pytest.raises( ramble.language.language_helpers.DirectiveError, match="Directive 'my_edit' in application 'mock_app' requires the function " "'no_return' to return a value", ): edit_func = edit_file("my_edit", "/path/f", function=no_return) edit_func(mock_app)
[docs] def test_edit_file_collision_avoidance(mock_app): def edit(content): return content + "1" def another_edit(content): return content + "2" edit_func1 = edit_file("e1", "/path/f1", function=edit) edit_func1(mock_app) edit_func2 = edit_file("e2", "/path/f2", function=another_edit) edit_func2(mock_app) assert "e1" in mock_app.custom_edit_functions assert "e2" in mock_app.custom_edit_functions source1 = mock_app.custom_edit_functions["e1"] source2 = mock_app.custom_edit_functions["e2"] assert "def custom_edit_e1_edit(content):" in source1 assert "def custom_edit_e2_another_edit(content):" in source2 template1 = mock_app.executables[frozenset()]["e1"].template[0] template2 = mock_app.executables[frozenset()]["e2"].template[0] assert "--function custom_edit_e1_edit" in template1 assert "--function custom_edit_e2_another_edit" in template2
[docs] def test_write_utilities(tmpdir): import os from ramble.workspace import workspace ws_root = str(tmpdir.mkdir("ws")) ws = workspace.Workspace(ws_root, True) ws.write_utilities() shared_util_dir = os.path.join(ws_root, "shared", "utilities") assert os.path.exists(shared_util_dir) # Base script assert os.path.exists(os.path.join(shared_util_dir, "_ramble_file_editor.py"))
[docs] def test_edit_file_missing_replace(mock_app): with pytest.raises( ramble.language.language_helpers.DirectiveError, match="requires both 'match' and 'replace' to be specified together", ): edit_func = edit_file("my_edit", "/path/f", match="foo") edit_func(mock_app)
[docs] def test_edit_file_missing_match(mock_app): with pytest.raises( ramble.language.language_helpers.DirectiveError, match="requires both 'match' and 'replace' to be specified together", ): edit_func = edit_file("my_edit", "/path/f", replace="foo") edit_func(mock_app)
[docs] def test_edit_file_no_actions(mock_app): with pytest.raises( ramble.language.language_helpers.DirectiveError, match="requires at least one action \\(match/replace, append, " "prepend, or function\\) to be specified", ): edit_func = edit_file("my_edit", "/path/f") edit_func(mock_app)
[docs] def test_edit_file_unretrievable_source(mock_app): # Dynamically created function has no source code file d = {} exec("def dynamic_func(content):\n return content", d) dynamic_func = d["dynamic_func"] with pytest.raises( ramble.language.language_helpers.DirectiveError, match="could not retrieve source for function", ): edit_func = edit_file("my_edit", "/path/f", function=dynamic_func) edit_func(mock_app)
[docs] def test_patch_file_directive(): from ramble.language.shared_language import patch_file # Create an app without executables to cover that branch class EmptyApp: def __init__(self): self.name = "empty_app" app = EmptyApp() patch_func = patch_file("my_patch", "/path/f", "/path/to/patch") patch_func(app) # Adding a second one to hit the line where executables dict exists patch_func2 = patch_file("my_patch2", "/path/f2", "/path/to/patch2") patch_func2(app) when_set = frozenset() assert "my_patch" in app.executables[when_set] assert "my_patch2" in app.executables[when_set] template = app.executables[when_set]["my_patch"].template[0] assert "--mode patch" in template
[docs] def test_edit_file_directive_empty_app(): # Same for edit_file class EmptyApp: def __init__(self): self.name = "empty_app" self.custom_edit_functions = {} app = EmptyApp() edit_func = edit_file("my_edit", "/path/f", match="a", replace="b") edit_func(app) assert "my_edit" in app.executables[frozenset()]