[Rt-commit] rt branch, 4.2/multi-value-cf-in-rest, created. rt-4.1.13-78-gce0a194
Alex Vandiver
alexmv at bestpractical.com
Tue Jul 2 18:46:10 EDT 2013
The branch, 4.2/multi-value-cf-in-rest has been created
at ce0a194ec583c4d5bc0fd08149283e88e758b8be (commit)
- Log -----------------------------------------------------------------
commit 887bdc6af4a940d2ec9a870cf2b4264f9c228219
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Wed Jul 6 15:39:30 2011 -0400
Add (failing) tests for escaping
diff --git a/t/web/command_line.t b/t/web/command_line.t
index 4572395..eea1930 100644
--- a/t/web/command_line.t
+++ b/t/web/command_line.t
@@ -265,6 +265,55 @@ expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
expect_like(qr/CF\.{MultipleCF$$}: '1,2\\'s,3'/i, 'Verified change');
+# Test escaping of quotes - generate (foo)(bar') with no escapes
+my $ticket = RT::Ticket->new($RT::SystemUser);
+expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo',bar'\"", "Changing CF with no slashes: 'foo',bar'");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+$ticket->Load($ticket_id);
+is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo"."\n"."bar'", "Direct value checks out");
+expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should be present)");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
+expect_like(qr/CF\.{MultipleCF$$}: foo/i, 'Verified change');
+
+# With one \, generate (foo',bar)
+expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo\\',bar'\"", "Changing CF to one slash: 'foo\\',bar'");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+$ticket->Load($ticket_id);
+is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo',bar", "Direct value checks out");
+expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should _not_ be present)");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
+expect_like(qr/CF\.{MultipleCF$$}: 'foo\\',bar'/i, 'Verified change');
+
+# With two \, generate (foo\)(bar')
+expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo\\\\',bar'\"", "Changing CF to two slashes: 'foo\\\\',bar'");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+$ticket->Load($ticket_id);
+is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo\\"."\n"."bar'", "Direct value checks out");
+expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should be present)");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
+expect_like(qr/CF\.{MultipleCF$$}: 'foo\\\\'/i, 'Verified change');
+
+# With three \, generate (foo\',bar)
+expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo\\\\\\',bar'\"", "Changing CF to three slashes: 'foo\\\\\\',bar'");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+$ticket->Load($ticket_id);
+is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo\\'bar", "Direct value checks out");
+expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should _not_ be present)");
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
+expect_like(qr/CF\.{MultipleCF$$}: 'foo\\\\\\',bar'/i, 'Verified change');
+
+# Check that we don't infinite-loop on 'foo'bar,baz
+TODO: {
+ todo_skip "Quotes not at comma boundries infinite-loop", 2;
+ expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo'bar,baz\"", 'Changing CF to have quotes not at commas');
+ expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+}
+
+
# ...
# change a ticket's ...[other properties]...
# ...
commit d9d923b7f0ebd22787199213d5b643077d846a56
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 11 12:40:35 2011 -0400
Update the tests to be more thorough
diff --git a/t/web/command_line.t b/t/web/command_line.t
index eea1930..5c2eb15 100644
--- a/t/web/command_line.t
+++ b/t/web/command_line.t
@@ -213,7 +213,7 @@ expect_send("edit ticket/$ticket_id set CF-myCF$$=1,2,3", 'Changing CF...');
expect_like(qr/Ticket $ticket_id updated/, 'Changed cf');
expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value');
expect_like(qr/CF\.{myCF$$}: 1,2,3/i, 'Verified change');
-expect_send("edit ticket/$ticket_id set CF-myCF$$=\"1's,2,3\"", 'Changing CF...');
+expect_send(qq{edit ticket/$ticket_id set CF-myCF$$="1's,2,3"}, 'Changing CF...');
expect_like(qr/Ticket $ticket_id updated/, 'Changed cf');
expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value');
expect_like(qr/CF\.{myCF$$}: 1's,2,3/i, 'Verified change');
@@ -238,79 +238,87 @@ expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
expect_like(qr/CF\.{MultipleCF$$}: b,\s*c,\s*o/i, 'Verified multiple cf change');
-expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'a,b,c'\" ", 'Changing CF...');
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change');
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...');
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change');
+sub multi_round_trip {
+ my ($op, $value, $regex) = @_;
+ $Test::Builder::Level++;
+ # The outer double quotes are for the argument parsing that the
+ # command-line does; the extra layer of escaping is to for them, as
+ # well. It is equivilent to the quoting that the shell would
+ # require.
+ my $quoted = $value;
+ $quoted =~ s/(["\\])/\\$1/g;
+ expect_send(qq{edit ticket/$ticket_id $op CF.{MultipleCF$$}="$quoted"}, qq{CF $op $value});
+ expect_like(qr/Ticket $ticket_id updated/, qq{Got expected "updated" answer});
+ expect_send(qq{show ticket/$ticket_id -f CF.{MultipleCF$$}}, qq{Sent "show"});
+ expect_like(qr/CF\.{MultipleCF$$}: $regex$/i, qq{Answer matches $regex});
+}
-expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=q{a,b,c}", 'Changing CF...');
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change');
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...');
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change');
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"'a,b,c'\"", 'Changing CF...');
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: \s*$/i, 'Verified change');
+# Test simple quoting
+my $ticket = RT::Ticket->new($RT::SystemUser);
+$ticket->Load($ticket_id);
+multi_round_trip(set => q|'a,b,c'|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(del => q|a|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(set => q|q{a,b,c}|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(del => q|a|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(del => q|'a,b,c'|, qr/\s*/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 0, "Now has no CF values");
+
+multi_round_trip(set => q|q{1,2's,3}|, qr/'1,2\\'s,3'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{1,2's,3}, "And that CF value is as expected");
+
+multi_round_trip(del => q|q{1,2's,3}|, qr/\s*/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 0, "Now has no CF values");
-expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"q{1,2's,3}\"", 'Changing CF...');
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: '1,2\\'s,3'/i, 'Verified change');
# Test escaping of quotes - generate (foo)(bar') with no escapes
-my $ticket = RT::Ticket->new($RT::SystemUser);
-expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo',bar'\"", "Changing CF with no slashes: 'foo',bar'");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-$ticket->Load($ticket_id);
-is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo"."\n"."bar'", "Direct value checks out");
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should be present)");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: foo/i, 'Verified change');
+multi_round_trip(set => q|'foo',bar'|, qr/foo,bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two values");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo|, "Direct value checks out");
+is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|bar'|, "Direct value checks out");
+multi_round_trip(del => q|bar'|, qr/foo/);
# With one \, generate (foo',bar)
-expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo\\',bar'\"", "Changing CF to one slash: 'foo\\',bar'");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-$ticket->Load($ticket_id);
-is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo',bar", "Direct value checks out");
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should _not_ be present)");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: 'foo\\',bar'/i, 'Verified change');
+
+# We obviously need two \s in the following q|| string in order to
+# generate a string with one actual \ in it; this causes the string to,
+# in general, have twice as many \s in it as we wish to test.
+multi_round_trip(set => q|'foo\\',bar'|, qr/'foo\\',bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Has one value");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo',bar|, "Direct value checks out");
# With two \, generate (foo\)(bar')
-expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo\\\\',bar'\"", "Changing CF to two slashes: 'foo\\\\',bar'");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-$ticket->Load($ticket_id);
-is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo\\"."\n"."bar'", "Direct value checks out");
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should be present)");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: 'foo\\\\'/i, 'Verified change');
+multi_round_trip(set => q|'foo\\\\',bar'|, qr/foo\\,bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two values");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo\\|, "Direct value checks out");
+is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|bar'|, "Direct value checks out");
+multi_round_trip(del => q|bar'|, qr/foo\\/);
# With three \, generate (foo\',bar)
-expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo\\\\\\',bar'\"", "Changing CF to three slashes: 'foo\\\\\\',bar'");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-$ticket->Load($ticket_id);
-is($ticket->CustomFieldValuesAsString("MultipleCF$$"), "foo\\'bar", "Direct value checks out");
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"bar'\"", "Stripping off bar' (should _not_ be present)");
-expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
-expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value');
-expect_like(qr/CF\.{MultipleCF$$}: 'foo\\\\\\',bar'/i, 'Verified change');
+multi_round_trip(set => q|'foo\\\\\\',bar'|, qr/'foo\\\\\\',bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Has one value");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo\\',bar|, "Direct value checks out");
-# Check that we don't infinite-loop on 'foo'bar,baz
+# Check that we don't infinite-loop on 'foo'bar,baz; this should be ('foo'bar)(baz)
TODO: {
- todo_skip "Quotes not at comma boundries infinite-loop", 2;
+ todo_skip "Quotes not at comma boundries infinite-loop", 5;
expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo'bar,baz\"", 'Changing CF to have quotes not at commas');
expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+ is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two value");
+ is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|'foo'bar|, "Direct value checks out");
+ is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|baz|, "Direct value checks out");
}
commit 24dac2e377ac4f88b9bfa86353410b05db534aee
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 11 12:41:39 2011 -0400
Compare base64 versions of the data, soas to not spew binary data on failure
diff --git a/t/web/command_line.t b/t/web/command_line.t
index 5c2eb15..1366ea3 100644
--- a/t/web/command_line.t
+++ b/t/web/command_line.t
@@ -593,7 +593,11 @@ sub check_attachment {
TODO: {
local $TODO = "Binary PNG content is getting mangled somewhere along the way"
if $attachment_path =~ /\.png$/;
- expect_is($attachment_content,"Attachment contains original text");
+ is(
+ MIME::Base64::encode_base64(Test::Expect::before()),
+ MIME::Base64::encode_base64($attachment_content),
+ "Attachment contains original text"
+ );
}
}
commit dec993fd23522ea79370e73e450567a9e2144bcb
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 11 12:15:17 2011 -0400
Only escape the output if we're going to quote it
diff --git a/share/html/REST/1.0/Forms/ticket/default b/share/html/REST/1.0/Forms/ticket/default
index 05a38a2..cd06e29 100644
--- a/share/html/REST/1.0/Forms/ticket/default
+++ b/share/html/REST/1.0/Forms/ticket/default
@@ -262,8 +262,8 @@ if (!keys(%data)) {
else {
while (my $v = $vals->Next()) {
my $content = $v->Content;
- $content =~ s/'/\\'/g;
if ( $v->Content =~ /,/ ) {
+ $content =~ s/([\\'])/\\$1/g;
push @out, q{'} . $content . q{'};
}
else {
commit 8a2cce9fcf4e5a3611f0e57788156ee60425212b
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 11 12:15:46 2011 -0400
Note that the vsplit code is duplicated
diff --git a/bin/rt.in b/bin/rt.in
index a344e11..04fd74f 100644
--- a/bin/rt.in
+++ b/bin/rt.in
@@ -1511,6 +1511,8 @@ sub vpush {
}
}
+# WARNING: this code is duplicated in lib/RT/Interface/REST.pm
+# If you change one, change both functions at once
# "Normalise" a hash key that's known to be multi-valued.
sub vsplit {
my ($val) = @_;
commit f3530b9d1121b53535a09c02819d6d9c2e3335ae
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 11 12:16:51 2011 -0400
Move to a regex-based quoting parser for vsplit
This also merges the 2.5 versions of the code.
diff --git a/bin/rt.in b/bin/rt.in
index 04fd74f..b9b3398 100644
--- a/bin/rt.in
+++ b/bin/rt.in
@@ -1515,47 +1515,52 @@ sub vpush {
# If you change one, change both functions at once
# "Normalise" a hash key that's known to be multi-valued.
sub vsplit {
- my ($val) = @_;
- my ($word, @words);
- my @values = ref $val eq 'ARRAY' ? @$val : $val;
-
- foreach my $line (map {split /\n/} @values) {
- # XXX: This should become a real parser, Ã la Text::ParseWords.
- $line =~ s/^\s+//;
- $line =~ s/\s+$//;
- my ( $a, $b ) = split /\s*,\s*/, $line, 2;
-
- while ($a) {
- no warnings 'uninitialized';
- if ( $a =~ /^'/ ) {
- my $s = $a;
- while ( $a !~ /'$/ || ( $a !~ /(\\\\)+'$/
- && $a =~ /(\\)+'$/ )) {
- ( $a, $b ) = split /\s*,\s*/, $b, 2;
- $s .= ',' . $a;
- }
- push @words, $s;
- }
- elsif ( $a =~ /^q{/ ) {
- my $s = $a;
- while ( $a !~ /}$/ ) {
- ( $a, $b ) =
- split /\s*,\s*/, $b, 2;
- $s .= ',' . $a;
- }
- $s =~ s/^q{/'/;
- $s =~ s/}/'/;
- push @words, $s;
+ my ($val, $strip) = @_;
+ my @words;
+ my @values = map {split /\n/} (ref $val eq 'ARRAY' ? @$val : $val);
+
+ foreach my $line (@values) {
+ while ($line =~ /\S/) {
+ $line =~ s/^
+ \s* # Trim leading whitespace
+ (?:
+ (") # Quoted string
+ ((?>[^\\"]*(?:\\.[^\\"]*)*))"
+ |
+ (') # Single-quoted string
+ ((?>[^\\']*(?:\\.[^\\']*)*))'
+ |
+ q{(.*?)} # A perl-ish q{} string; this does
+ # no paren balancing, however, and
+ # only exists for back-compat
+ |
+ (.*?) # Anything else, until the next comma
+ )
+ \s* # Trim trailing whitespace
+ (?:
+ \Z # Finish at end-of-line
+ |
+ , # Or a comma
+ )
+ //xs or last; # There should be no way this match
+ # fails, but add a failsafe to
+ # prevent infinite-looping if it
+ # somehow does.
+ my ($quote, $quoted) = ($1 ? ($1, $2) : $3 ? ($3, $4) : ('', $5 || $6));
+ # Only unquote the quote character, or the backslash -- and
+ # only if we were originally quoted..
+ if ($5) {
+ $quoted =~ s/([\\'])/\\$1/g;
+ $quote = "'";
}
- else {
- push @words, $a;
+ if ($strip) {
+ $quoted =~ s/\\([\\$quote])/$1/g if $quote;
+ push @words, $quoted;
+ } else {
+ push @words, "$quote$quoted$quote";
}
- ( $a, $b ) = split /\s*,\s*/, $b, 2;
}
-
-
}
-
return \@words;
}
diff --git a/lib/RT/Interface/REST.pm b/lib/RT/Interface/REST.pm
index 5f8ff99..bc908bb 100644
--- a/lib/RT/Interface/REST.pm
+++ b/lib/RT/Interface/REST.pm
@@ -282,17 +282,52 @@ sub vpush {
# "Normalise" a hash key that's known to be multi-valued.
sub vsplit {
- my ($val) = @_;
+ my ($val, $strip) = @_;
my @words;
-
- foreach my $line (map {split /\n/} (ref $val eq 'ARRAY') ? @$val : ($val||''))
- {
- # XXX: This should become a real parser, ? la Text::ParseWords.
- $line =~ s/^\s+//;
- $line =~ s/\s+$//;
- push @words, split /\s*,\s*/, $line;
+ my @values = map {split /\n/} (ref $val eq 'ARRAY' ? @$val : $val);
+
+ foreach my $line (@values) {
+ while ($line =~ /\S/) {
+ $line =~ s/^
+ \s* # Trim leading whitespace
+ (?:
+ (") # Quoted string
+ ((?>[^\\"]*(?:\\.[^\\"]*)*))"
+ |
+ (') # Single-quoted string
+ ((?>[^\\']*(?:\\.[^\\']*)*))'
+ |
+ q{(.*?)} # A perl-ish q{} string; this does
+ # no paren balancing, however, and
+ # only exists for back-compat
+ |
+ (.*?) # Anything else, until the next comma
+ )
+ \s* # Trim trailing whitespace
+ (?:
+ \Z # Finish at end-of-line
+ |
+ , # Or a comma
+ )
+ //xs or last; # There should be no way this match
+ # fails, but add a failsafe to
+ # prevent infinite-looping if it
+ # somehow does.
+ my ($quote, $quoted) = ($1 ? ($1, $2) : $3 ? ($3, $4) : ('', $5 || $6));
+ # Only unquote the quote character, or the backslash -- and
+ # only if we were originally quoted..
+ if ($5) {
+ $quoted =~ s/([\\'])/\\$1/g;
+ $quote = "'";
+ }
+ if ($strip) {
+ $quoted =~ s/\\([\\$quote])/$1/g if $quote;
+ push @words, $quoted;
+ } else {
+ push @words, "$quote$quoted$quote";
+ }
+ }
}
-
return \@words;
}
diff --git a/share/html/REST/1.0/Forms/ticket/default b/share/html/REST/1.0/Forms/ticket/default
index cd06e29..d41215e 100644
--- a/share/html/REST/1.0/Forms/ticket/default
+++ b/share/html/REST/1.0/Forms/ticket/default
@@ -391,37 +391,7 @@ else {
$s =~ s/^# // if defined $s;
}
else {
- my @new;
- my ( $a, $b ) = split /\s*,\s*/, $val, 2;
- while ($a) {
- no warnings 'uninitialized';
- if ( $a =~ /^'/ ) {
- my $s = $a;
- while ( $a !~ /'$/ || ( $a !~ /(\\\\)+'$/
- && $a =~ /(\\)+'$/ ) ) {
- ( $a, $b ) = split /\s*,\s*/, $b, 2;
- $s .= ',' . $a;
- }
- $s =~ s/^'//;
- $s =~ s/'$//;
- $s =~ s/\\'/'/g;
- push @new, $s;
- }
- elsif ( $a =~ /^q{/ ) {
- my $s = $a;
- while ( $a !~ /}$/ ) {
- ( $a, $b ) = split /\s*,\s*/, $b, 2;
- $s .= ',' . $a;
- }
- $s =~ s/^q{//;
- $s =~ s/}//;
- push @new, $s;
- }
- else {
- push @new, $a;
- }
- ( $a, $b ) = split /\s*,\s*/, $b, 2;
- }
+ my @new = @{vsplit($val, 1)};
my %new;
$new{$_}++ for @new;
commit ce0a194ec583c4d5bc0fd08149283e88e758b8be
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 11 12:40:58 2011 -0400
Un-TODO the tests
diff --git a/t/web/command_line.t b/t/web/command_line.t
index 1366ea3..dcff076 100644
--- a/t/web/command_line.t
+++ b/t/web/command_line.t
@@ -312,14 +312,11 @@ is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Has one value");
is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo\\',bar|, "Direct value checks out");
# Check that we don't infinite-loop on 'foo'bar,baz; this should be ('foo'bar)(baz)
-TODO: {
- todo_skip "Quotes not at comma boundries infinite-loop", 5;
- expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo'bar,baz\"", 'Changing CF to have quotes not at commas');
- expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
- is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two value");
- is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|'foo'bar|, "Direct value checks out");
- is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|baz|, "Direct value checks out");
-}
+expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo'bar,baz\"", 'Changing CF to have quotes not at commas');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf');
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two value");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|'foo'bar|, "Direct value checks out");
+is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|baz|, "Direct value checks out");
# ...
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list