codeplain 0.3.13.dev35__tar.gz → 0.3.13.dev37__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/publish-dev-to-pypi.yml +1 -1
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/PKG-INFO +1 -1
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/file_utils.py +17 -1
- codeplain-0.3.13.dev37/tests/test_file_utils.py +174 -0
- codeplain-0.3.13.dev35/tests/test_file_utils.py +0 -92
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.claude/settings.json +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.flake8 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/dependabot.yml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/e2e.yml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/lint-and-test.yml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/lint-powershell.yml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/publish-install-script.yml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/publish-to-pypi.yml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.gitignore +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.vscode/launch.json +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.vscode/settings.json +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/CLAUDE.md +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/CONTRIBUTING.md +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/LICENSE +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/README.md +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/change_detection.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/cli_output/__init__.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/cli_output/dry_run.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/cli_output/render_summary.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/cli_output/status.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/codeplain_REST_api.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/concept_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/config/__init__.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/config/system_config.yaml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/conformance_fix_journal.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/diff_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/docs/generate_cli.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/docs/plain2code_cli.md +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/docs/starting_a_plain_project_from_scratch.md +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/event_bus.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_golang/config.yaml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_golang/run.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_python/config.yaml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_python/hello_world_python.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_python/run.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/config.yaml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/hello_world_react.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/run.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/run.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/git_preflight.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/git_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/install/bash/examples.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/install/bash/install.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/install/bash/walkthrough.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/install/powershell/examples.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/install/powershell/install.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/install/powershell/walkthrough.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/memory_management.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/metadata_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/module_renderer.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/partial_rendering.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/path_resolution.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_arguments.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_cli.md +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_console.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_events.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_exceptions.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_logger.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_nodes.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_read_config.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_state.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_telemetry.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain2code_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain_file.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain_modules.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/plain_spec.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/pyproject.toml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/pytest.ini +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/__init__.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/base_action.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/commit_implementation_code_changes.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/create_dist.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/distill_conformance_test_memory.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/exit_with_error.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/finish_functional_requirement.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/fix_conformance_test.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/fix_unit_tests.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/prepare_repositories.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/prepare_testing_environment.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/refactor_code.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/render_conformance_tests.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/render_functional_requirement.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/run_conformance_tests.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/run_unit_tests.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/summarize_conformance_tests.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/agent_tools.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/code_renderer.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/conformance_tests.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/implementation_code_helpers.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/render_context.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/render_types.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/render_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/state_machine_config.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/states.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/triggers.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/requirements.txt +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/resources/codeplain_overview.png +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/resources/plain_example.png +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/standard_template_library/golang-console-app-template.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/standard_template_library/python-console-app-template.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/standard_template_library/typescript-react-app-template.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/system_config.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_conformance_tests_cypress.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_conformance_tests_golang.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_conformance_tests_python.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_conformance_tests_python.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_flutter.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_flutter.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_golang.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_golang.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_python.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_python.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_react.ps1 +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_unittests_react.sh +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/__init__.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/conftest.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/acceptance_tests_warning/main_requiring_acceptance_tests.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/acceptance_tests_warning/required_with_acceptance_tests.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/circular_imports_1.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/circular_imports_2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/circular_imports_main.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/diamond_import_1.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/diamond_import_2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/diamond_import_common.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/diamond_imports_main.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/import_with_functionalities.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/imports/non_existent_import.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/partial_rendering/pr_code_var.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/partial_rendering/pr_implement.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/partial_rendering/pr_leaf.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/partial_rendering/pr_middle.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/partial_rendering/pr_root.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/partial_rendering/pr_solo.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/invalid_specification_order.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/plain_source_with_missing_link.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/cyclic_definitions.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_defaults_exported.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_imported_exported.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_inherited_reexported.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_malformed.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_missing_definition.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_missing_definition_example.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_multiple_per_bullet.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_multiple_per_bullet_undefined.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_no_definitions.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_not_declared.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_not_declared_example.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/requires_without_definitions_example.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/topological_sort.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/circular_requires_main.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/circular_requires_sub.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/diamond_requires_1.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/diamond_requires_2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/diamond_requires_common.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/diamond_requires_main.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/independent_requires_1.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/independent_requires_2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/independent_requires_main.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/non_existent_require.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/normal_requires_1.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/normal_requires_2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/normal_requires_common.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/requires/normal_requires_main.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/sample_base64_image.txt +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/simple.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/templates/block_level_include.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/templates/code_variables.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/templates/header.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/templates/implement.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/templates/implement_2.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/templates/template_include.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/data/templates/test_hardest_problem.plain +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/e2e/Dockerfile +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/e2e/conftest.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/e2e/test_hello_world_python.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/e2e/test_hello_world_python_windows.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_agent_tools.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_arg_provenance.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_change_detection.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_cli_output.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_conformance_fix_journal.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_console_log_styles.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_distill_conformance_test_memory.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_dry_run_link_validation.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_fix_unit_tests_action.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_fix_unit_tests_conformance_context.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_folder_path_resolution.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_git_preflight.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_git_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_headless_logging.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_imports.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_log_file_name_resolution.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_logging_config_path_resolution.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_partial_rendering.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_path_resolution.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_plain2code.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_plain2code_state.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_plain2code_utils.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_plain_modules.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_plainfile.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_plainfileparser.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_plainspec.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_prepare_repositories_layout.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_render_finished_report.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_requires.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_resolve_config_file.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_script_path_resolution.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_system_config.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_telemetry.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_terminal_attachment.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_tui_components.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_tui_usage.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tests/test_usage_summary.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/__init__.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/components.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/models.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/plain2code_tui.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/plain_module_render_choice_tui.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/spinner.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/state_handlers.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/styles.css +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/tui/widget_helpers.py +0 -0
- {codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/usage_summary.py +0 -0
|
@@ -142,7 +142,21 @@ def get_existing_files_content(build_folder, existing_files):
|
|
|
142
142
|
return existing_files_content
|
|
143
143
|
|
|
144
144
|
|
|
145
|
+
def ensure_final_newline(content: str) -> str:
|
|
146
|
+
"""Ends non-empty text with a newline, as linters expect (e.g. RuboCop, ESLint eol-last, Ruff W292)."""
|
|
147
|
+
if content and not content.endswith("\n"):
|
|
148
|
+
return content + "\n"
|
|
149
|
+
return content
|
|
150
|
+
|
|
151
|
+
|
|
145
152
|
def store_response_files(target_folder, response_files, existing_files):
|
|
153
|
+
"""Writes the files returned by the API to target_folder. None content deletes the file.
|
|
154
|
+
|
|
155
|
+
Every written file ends with a newline - whole-file rewrites come back from the API without one. The
|
|
156
|
+
added newline is also written back into response_files, so callers that diff response_files against
|
|
157
|
+
the folder afterwards see exactly what is on disk. Content is written byte-for-byte, without newline
|
|
158
|
+
translation, so the disk matches response_files on every platform.
|
|
159
|
+
"""
|
|
146
160
|
for file_name in response_files:
|
|
147
161
|
full_file_name = os.path.join(target_folder, file_name)
|
|
148
162
|
|
|
@@ -156,9 +170,11 @@ def store_response_files(target_folder, response_files, existing_files):
|
|
|
156
170
|
|
|
157
171
|
continue
|
|
158
172
|
|
|
173
|
+
response_files[file_name] = ensure_final_newline(response_files[file_name])
|
|
174
|
+
|
|
159
175
|
os.makedirs(os.path.dirname(full_file_name), exist_ok=True)
|
|
160
176
|
|
|
161
|
-
with open(full_file_name, "w", encoding="utf-8") as f:
|
|
177
|
+
with open(full_file_name, "w", encoding="utf-8", newline="") as f:
|
|
162
178
|
f.write(response_files[file_name])
|
|
163
179
|
|
|
164
180
|
if file_name not in existing_files:
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
import file_utils
|
|
7
|
+
from diff_utils import get_code_diff
|
|
8
|
+
from file_utils import get_existing_files_content, load_linked_resources, store_response_files
|
|
9
|
+
from plain2code_exceptions import UnsupportedBase64Content, UnsupportedResourceType
|
|
10
|
+
from plain2code_utils import MAX_BASE64_BLOB_LENGTH
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture
|
|
14
|
+
def template_dir():
|
|
15
|
+
with tempfile.TemporaryDirectory() as d:
|
|
16
|
+
yield d
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_load_linked_resources_text_file(template_dir):
|
|
20
|
+
file_path = os.path.join(template_dir, "notes.md")
|
|
21
|
+
with open(file_path, "w") as f:
|
|
22
|
+
f.write("# hello")
|
|
23
|
+
|
|
24
|
+
result = load_linked_resources([template_dir], [{"text": "Notes", "target": "notes.md"}], "my_thing")
|
|
25
|
+
|
|
26
|
+
assert result == {"notes.md": "# hello"}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_load_linked_resources_binary_file_raises_unsupported_resource_type(template_dir):
|
|
30
|
+
file_path = os.path.join(template_dir, "icon.png")
|
|
31
|
+
with open(file_path, "wb") as f:
|
|
32
|
+
f.write(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\xff\xfe\xfd")
|
|
33
|
+
|
|
34
|
+
with pytest.raises(UnsupportedResourceType) as exc_info:
|
|
35
|
+
load_linked_resources([template_dir], [{"text": "Icon", "target": "icon.png"}], "my_thing")
|
|
36
|
+
|
|
37
|
+
assert "icon.png" in str(exc_info.value)
|
|
38
|
+
assert "binary file" in str(exc_info.value)
|
|
39
|
+
assert "my_thing" in str(exc_info.value)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_load_linked_resources_missing_file_raises_file_not_found(template_dir):
|
|
43
|
+
with pytest.raises(FileNotFoundError):
|
|
44
|
+
load_linked_resources([template_dir], [{"text": "Missing", "target": "missing.md"}], "my_thing")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_load_linked_resources_base64_blob_raises(template_dir):
|
|
48
|
+
file_path = os.path.join(template_dir, "request.txt")
|
|
49
|
+
with open(file_path, "w") as f:
|
|
50
|
+
f.write("curl -d 'selfie_image=" + "A" * (MAX_BASE64_BLOB_LENGTH + 100) + "'")
|
|
51
|
+
|
|
52
|
+
with pytest.raises(UnsupportedBase64Content) as exc_info:
|
|
53
|
+
load_linked_resources([template_dir], [{"text": "Request", "target": "request.txt"}], "my_thing")
|
|
54
|
+
|
|
55
|
+
assert "request.txt" in str(exc_info.value)
|
|
56
|
+
assert "my_thing" in str(exc_info.value)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_load_linked_resources_small_base64_allowed(template_dir):
|
|
60
|
+
file_path = os.path.join(template_dir, "token.txt")
|
|
61
|
+
with open(file_path, "w") as f:
|
|
62
|
+
f.write("token=" + "A" * (MAX_BASE64_BLOB_LENGTH - 100))
|
|
63
|
+
|
|
64
|
+
result = load_linked_resources([template_dir], [{"text": "Token", "target": "token.txt"}], "my_thing")
|
|
65
|
+
|
|
66
|
+
assert "token.txt" in result
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_load_linked_resources_real_base64_image_raises(template_dir):
|
|
70
|
+
# Real base64-encoded JPEG that made Gemini 3 fail, inlined into a curl example resource.
|
|
71
|
+
sample_path = os.path.join(os.path.dirname(__file__), "data", "sample_base64_image.txt")
|
|
72
|
+
with open(sample_path) as f:
|
|
73
|
+
blob = f.read()
|
|
74
|
+
|
|
75
|
+
file_path = os.path.join(template_dir, "face_match_request.txt")
|
|
76
|
+
with open(file_path, "w") as f:
|
|
77
|
+
f.write(f"curl -d 'selfie_image={blob}' https://example.com/face-match")
|
|
78
|
+
|
|
79
|
+
with pytest.raises(UnsupportedBase64Content) as exc_info:
|
|
80
|
+
load_linked_resources([template_dir], [{"text": "Request", "target": "face_match_request.txt"}], "face_match")
|
|
81
|
+
|
|
82
|
+
assert "face_match_request.txt" in str(exc_info.value)
|
|
83
|
+
assert str(len(blob)) in str(exc_info.value)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_store_response_files_writes_unicode_as_utf8(template_dir):
|
|
87
|
+
"""A non-cp1252 character (📍 U+1F4CD) is written as UTF-8, whatever the platform's default encoding."""
|
|
88
|
+
content = "Location 📍 marker\n"
|
|
89
|
+
store_response_files(template_dir, {"notes.md": content}, [])
|
|
90
|
+
|
|
91
|
+
file_path = os.path.join(template_dir, "notes.md")
|
|
92
|
+
with open(file_path, "rb") as f:
|
|
93
|
+
assert f.read().decode("utf-8") == content
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _read_bytes(folder, file_name):
|
|
97
|
+
"""Returns a file's content exactly as stored on disk, without newline translation."""
|
|
98
|
+
with open(os.path.join(folder, file_name), "rb") as f:
|
|
99
|
+
return f.read().decode("utf-8")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@pytest.mark.parametrize(
|
|
103
|
+
"content, expected",
|
|
104
|
+
[
|
|
105
|
+
("class Foo\nend", "class Foo\nend\n"),
|
|
106
|
+
("class Foo\nend\n", "class Foo\nend\n"),
|
|
107
|
+
("class Foo\nend\n\n", "class Foo\nend\n\n"),
|
|
108
|
+
("class Foo\r\nend\r\n", "class Foo\r\nend\r\n"),
|
|
109
|
+
("", ""),
|
|
110
|
+
],
|
|
111
|
+
)
|
|
112
|
+
def test_store_response_files_ends_every_text_file_with_a_newline(template_dir, content, expected):
|
|
113
|
+
"""A missing final newline is added, as linters such as RuboCop, ESLint and Ruff require.
|
|
114
|
+
|
|
115
|
+
An existing final newline is not doubled, and empty content stays empty.
|
|
116
|
+
"""
|
|
117
|
+
store_response_files(template_dir, {"app/foo.rb": content}, [])
|
|
118
|
+
|
|
119
|
+
assert _read_bytes(template_dir, "app/foo.rb") == expected
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_store_response_files_hands_back_the_content_it_wrote(template_dir):
|
|
123
|
+
"""response_files holds the content as written, so diffs taken after storing match the disk.
|
|
124
|
+
|
|
125
|
+
The fix journal and the conformance fixes handed to the unit tests fixer take such diffs.
|
|
126
|
+
"""
|
|
127
|
+
response_files = {"app/foo.rb": "class Foo\nend", "app/bar.rb": "class Bar\nend\n"}
|
|
128
|
+
|
|
129
|
+
store_response_files(template_dir, response_files, [])
|
|
130
|
+
|
|
131
|
+
assert response_files == {"app/foo.rb": "class Foo\nend\n", "app/bar.rb": "class Bar\nend\n"}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_rewriting_a_file_without_its_final_newline_does_not_change_it(template_dir):
|
|
135
|
+
"""A rewrite that drops only the final newline leaves the file byte-identical and produces no diff."""
|
|
136
|
+
existing_files = store_response_files(template_dir, {"app/foo.rb": "class Foo\nend\n"}, [])
|
|
137
|
+
existing_files_content = get_existing_files_content(template_dir, existing_files)
|
|
138
|
+
|
|
139
|
+
rewrite = {"app/foo.rb": "class Foo\nend"}
|
|
140
|
+
store_response_files(template_dir, rewrite, existing_files)
|
|
141
|
+
|
|
142
|
+
assert get_existing_files_content(template_dir, existing_files) == existing_files_content
|
|
143
|
+
assert get_code_diff(rewrite, existing_files_content) == {}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_store_response_files_still_deletes_a_file_whose_content_is_none(template_dir):
|
|
147
|
+
"""None content still deletes the file and removes it from existing_files, and is not turned into a newline."""
|
|
148
|
+
existing_files = store_response_files(template_dir, {"app/foo.rb": "class Foo\nend\n"}, [])
|
|
149
|
+
|
|
150
|
+
response_files = {"app/foo.rb": None}
|
|
151
|
+
store_response_files(template_dir, response_files, existing_files)
|
|
152
|
+
|
|
153
|
+
assert not os.path.exists(os.path.join(template_dir, "app/foo.rb"))
|
|
154
|
+
assert existing_files == []
|
|
155
|
+
assert response_files == {"app/foo.rb": None}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_store_response_files_writes_the_same_bytes_where_text_mode_writes_crlf(template_dir, monkeypatch):
|
|
159
|
+
"""Files hold exactly the normalized content even where text mode writes CRLF line endings (native Windows)."""
|
|
160
|
+
# Imported here: isort 8 and isort 9 disagree on which section a top-level `import _pyio` belongs to.
|
|
161
|
+
import _pyio
|
|
162
|
+
|
|
163
|
+
# Python's reference io (_pyio) takes its line separator from os.linesep, so here it translates like Windows.
|
|
164
|
+
monkeypatch.setattr(os, "linesep", "\r\n")
|
|
165
|
+
monkeypatch.setattr(file_utils, "open", _pyio.open, raising=False)
|
|
166
|
+
with _pyio.open(os.path.join(template_dir, "probe.txt"), "w") as probe:
|
|
167
|
+
probe.write("\n")
|
|
168
|
+
assert _read_bytes(template_dir, "probe.txt") == "\r\n"
|
|
169
|
+
|
|
170
|
+
response_files = {"app/foo.rb": "class Foo\nend", "app/bar.rb": "class Bar\r\nend\r\n"}
|
|
171
|
+
store_response_files(template_dir, response_files, [])
|
|
172
|
+
|
|
173
|
+
assert _read_bytes(template_dir, "app/foo.rb") == response_files["app/foo.rb"] == "class Foo\nend\n"
|
|
174
|
+
assert _read_bytes(template_dir, "app/bar.rb") == response_files["app/bar.rb"] == "class Bar\r\nend\r\n"
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import tempfile
|
|
3
|
-
|
|
4
|
-
import pytest
|
|
5
|
-
|
|
6
|
-
from file_utils import load_linked_resources, store_response_files
|
|
7
|
-
from plain2code_exceptions import UnsupportedBase64Content, UnsupportedResourceType
|
|
8
|
-
from plain2code_utils import MAX_BASE64_BLOB_LENGTH
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@pytest.fixture
|
|
12
|
-
def template_dir():
|
|
13
|
-
with tempfile.TemporaryDirectory() as d:
|
|
14
|
-
yield d
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_load_linked_resources_text_file(template_dir):
|
|
18
|
-
file_path = os.path.join(template_dir, "notes.md")
|
|
19
|
-
with open(file_path, "w") as f:
|
|
20
|
-
f.write("# hello")
|
|
21
|
-
|
|
22
|
-
result = load_linked_resources([template_dir], [{"text": "Notes", "target": "notes.md"}], "my_thing")
|
|
23
|
-
|
|
24
|
-
assert result == {"notes.md": "# hello"}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def test_load_linked_resources_binary_file_raises_unsupported_resource_type(template_dir):
|
|
28
|
-
file_path = os.path.join(template_dir, "icon.png")
|
|
29
|
-
with open(file_path, "wb") as f:
|
|
30
|
-
f.write(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\xff\xfe\xfd")
|
|
31
|
-
|
|
32
|
-
with pytest.raises(UnsupportedResourceType) as exc_info:
|
|
33
|
-
load_linked_resources([template_dir], [{"text": "Icon", "target": "icon.png"}], "my_thing")
|
|
34
|
-
|
|
35
|
-
assert "icon.png" in str(exc_info.value)
|
|
36
|
-
assert "binary file" in str(exc_info.value)
|
|
37
|
-
assert "my_thing" in str(exc_info.value)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def test_load_linked_resources_missing_file_raises_file_not_found(template_dir):
|
|
41
|
-
with pytest.raises(FileNotFoundError):
|
|
42
|
-
load_linked_resources([template_dir], [{"text": "Missing", "target": "missing.md"}], "my_thing")
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def test_load_linked_resources_base64_blob_raises(template_dir):
|
|
46
|
-
file_path = os.path.join(template_dir, "request.txt")
|
|
47
|
-
with open(file_path, "w") as f:
|
|
48
|
-
f.write("curl -d 'selfie_image=" + "A" * (MAX_BASE64_BLOB_LENGTH + 100) + "'")
|
|
49
|
-
|
|
50
|
-
with pytest.raises(UnsupportedBase64Content) as exc_info:
|
|
51
|
-
load_linked_resources([template_dir], [{"text": "Request", "target": "request.txt"}], "my_thing")
|
|
52
|
-
|
|
53
|
-
assert "request.txt" in str(exc_info.value)
|
|
54
|
-
assert "my_thing" in str(exc_info.value)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def test_load_linked_resources_small_base64_allowed(template_dir):
|
|
58
|
-
file_path = os.path.join(template_dir, "token.txt")
|
|
59
|
-
with open(file_path, "w") as f:
|
|
60
|
-
f.write("token=" + "A" * (MAX_BASE64_BLOB_LENGTH - 100))
|
|
61
|
-
|
|
62
|
-
result = load_linked_resources([template_dir], [{"text": "Token", "target": "token.txt"}], "my_thing")
|
|
63
|
-
|
|
64
|
-
assert "token.txt" in result
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def test_load_linked_resources_real_base64_image_raises(template_dir):
|
|
68
|
-
# Real base64-encoded JPEG that made Gemini 3 fail, inlined into a curl example resource.
|
|
69
|
-
sample_path = os.path.join(os.path.dirname(__file__), "data", "sample_base64_image.txt")
|
|
70
|
-
with open(sample_path) as f:
|
|
71
|
-
blob = f.read()
|
|
72
|
-
|
|
73
|
-
file_path = os.path.join(template_dir, "face_match_request.txt")
|
|
74
|
-
with open(file_path, "w") as f:
|
|
75
|
-
f.write(f"curl -d 'selfie_image={blob}' https://example.com/face-match")
|
|
76
|
-
|
|
77
|
-
with pytest.raises(UnsupportedBase64Content) as exc_info:
|
|
78
|
-
load_linked_resources([template_dir], [{"text": "Request", "target": "face_match_request.txt"}], "face_match")
|
|
79
|
-
|
|
80
|
-
assert "face_match_request.txt" in str(exc_info.value)
|
|
81
|
-
assert str(len(blob)) in str(exc_info.value)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def test_store_response_files_writes_unicode_as_utf8(template_dir):
|
|
85
|
-
# Content with a non-cp1252 character (📍 U+1F4CD) must be written as UTF-8
|
|
86
|
-
# regardless of the platform's default text encoding (e.g. cp1252 on Windows).
|
|
87
|
-
content = "Location 📍 marker"
|
|
88
|
-
store_response_files(template_dir, {"notes.md": content}, [])
|
|
89
|
-
|
|
90
|
-
file_path = os.path.join(template_dir, "notes.md")
|
|
91
|
-
with open(file_path, "rb") as f:
|
|
92
|
-
assert f.read().decode("utf-8") == content
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/nofity-slack-on-main-merge.yml
RENAMED
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/.github/workflows/publish-install-script.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/docs/starting_a_plain_project_from_scratch.md
RENAMED
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_golang/config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_golang/run.sh
RENAMED
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_python/config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_python/run.sh
RENAMED
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/examples/example_hello_world_react/config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/fix_conformance_test.py
RENAMED
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/prepare_repositories.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/render_conformance_tests.py
RENAMED
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/actions/run_conformance_tests.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/render_machine/implementation_code_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codeplain-0.3.13.dev35 → codeplain-0.3.13.dev37}/test_scripts/run_conformance_tests_cypress.ps1
RENAMED
|
File without changes
|