From 7313aa2268e811b4774f3899b20ae6d57b3e08f7 Mon Sep 17 00:00:00 2001 From: Nick Anderson Date: Mon, 3 Aug 2026 16:57:21 -0500 Subject: [PATCH] Fixed insert_lines ignoring include_end_delimiter when locating the region The insertion path treats the selected region as the half-open range [begin_ptr, end_ptr), so the end delimiter was never inside it. Inserting after the last line of a region built with include_end_delimiter => "true" landed above the end delimiter instead of below it. Insertion now moves the bound the way DeletePromisedLinesMatching() already does. That attribute previously had no effect at all on insert_lines, so the default of inserting before an excluded end delimiter is unchanged. Acceptance test 31_tickets/CFE-3988/2 covers that default and 31_tickets/CFE-3988/1 is no longer a soft failure. Ticket: CFE-3988 Changelog: Title Co-Authored-By: Claude Opus 5 (1M context) --- cf-agent/files_editline.c | 7 ++ .../acceptance/31_tickets/CFE-3988/1/test.cf | 4 - .../31_tickets/CFE-3988/2/before_test.xml.txt | 49 ++++++++++++ .../acceptance/31_tickets/CFE-3988/2/test.cf | 78 +++++++++++++++++++ 4 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 tests/acceptance/31_tickets/CFE-3988/2/before_test.xml.txt create mode 100644 tests/acceptance/31_tickets/CFE-3988/2/test.cf diff --git a/cf-agent/files_editline.c b/cf-agent/files_editline.c index dd4826d3ed..39ecde4e45 100644 --- a/cf-agent/files_editline.c +++ b/cf-agent/files_editline.c @@ -765,6 +765,13 @@ static PromiseResult VerifyLineInsertions(EvalContext *ctx, const Promise *pp, E return result; } + /* The region is half open, [begin_ptr, end_ptr), so including the end + * delimiter means moving the bound past it -- after the NULL check above. */ + if (a.region.include_end != 0 && end_ptr != NULL) + { + end_ptr = end_ptr->next; + } + if (allow_multi_lines) { // promise to insert duplicates on first pass only diff --git a/tests/acceptance/31_tickets/CFE-3988/1/test.cf b/tests/acceptance/31_tickets/CFE-3988/1/test.cf index b41ecaa0d1..ecb73b3aa8 100644 --- a/tests/acceptance/31_tickets/CFE-3988/1/test.cf +++ b/tests/acceptance/31_tickets/CFE-3988/1/test.cf @@ -25,10 +25,6 @@ bundle agent test string => "edit_line should insert after the last matched line when selecting a region where the end delimiter is included", meta => { "CFE-3988" }; - "test_soft_fail" - string => "any", - meta => { "CFE-3988" }; - vars: "seed_file" string => "$(this.promise_dirname)/before_test.xml.txt"; "test_file" string => "$(G.testfile)"; diff --git a/tests/acceptance/31_tickets/CFE-3988/2/before_test.xml.txt b/tests/acceptance/31_tickets/CFE-3988/2/before_test.xml.txt new file mode 100644 index 0000000000..e757010baa --- /dev/null +++ b/tests/acceptance/31_tickets/CFE-3988/2/before_test.xml.txt @@ -0,0 +1,49 @@ + + + + Atlassian JIRA Web Application + The Atlassian JIRA web application - see http://www.atlassian.com/software/jira for more information + + + + + + + + + + JiraImportProgressFilter + com.atlassian.jira.web.filters.JiraImportProgressFilter + + + + + + JiraFirstFilter + com.atlassian.jira.web.filters.JiraFirstFilter + + + + + + JiraLastFilter + com.atlassian.jira.web.filters.JiraLastFilter + + + + + diff --git a/tests/acceptance/31_tickets/CFE-3988/2/test.cf b/tests/acceptance/31_tickets/CFE-3988/2/test.cf new file mode 100644 index 0000000000..9aaa16d1ea --- /dev/null +++ b/tests/acceptance/31_tickets/CFE-3988/2/test.cf @@ -0,0 +1,78 @@ +body file control +{ + inputs => { "../../../default.sub.cf" }; +} + +bundle agent __main__ +# If this is the policy entry (cf-agent --file) then this bundle will be run by default. +{ + methods: + "bundlesequence" usebundle => default("$(this.promise_filename)"); +} + +bundle agent init +{ + files: + # Seed the file we will exercise the test on + "$(G.testfile)" + copy_from => local_dcp("$(this.promise_dirname)/before_test.xml.txt"); +} + +bundle agent test +{ + meta: + "description" + string => "edit_line should insert before the end delimiter when the end delimiter is not included in the region", + meta => { "CFE-3988" }; + + vars: + "seed_file" string => "$(this.promise_dirname)/before_test.xml.txt"; + "test_file" string => "$(G.testfile)"; + + files: + "$(test_file)" edit_line => CFE_3988_excluded_end; +} + +bundle agent check +# @brief Companion to case 1. With include_end_delimiter left at its default of +# false the end delimiter is not part of the region, so the last matching line +# is the one before it and the insertion must land above the delimiter. +{ + methods: + # We expect to find lines that look something like this: + # THIS MUST BE THE LAST FILTER IN THE DEFINED CHAIN + #INSERT ME + # ===================================================== --> + "Pass/FAIL" + usebundle => dcs_check_regcmp( + ".*\s+THIS MUST BE THE LAST FILTER IN THE DEFINED CHAIN\RINSERT\sME\R\s+=+\s+-->.*", + readfile("$(test.test_file)"), + $(this.promise_filename), + "no" + ); +} + +bundle edit_line CFE_3988_excluded_end +{ + insert_lines: + "INSERT ME" + select_region => my_comment_last_filter_excluded_end, + location => my_location_after_comment_last_filter; +} + +body location my_location_after_comment_last_filter +# @brief Editing occurs after the last line in the selected region +{ + before_after => "after"; + first_last => "last"; + select_line_matching => ".*"; +} + +body select_region my_comment_last_filter_excluded_end +{ + select_start => "\s+THIS MUST BE THE LAST FILTER IN THE DEFINED CHAIN"; + select_end => "\s+=+\s+-->"; + include_start_delimiter => "true"; + include_end_delimiter => "false"; + select_end_match_eof => "false"; +}