Преглед на файлове

Enable ProhibitComplexRegexes and ProhibitBuiltinHomonyms

ProhibitComplexRegexes allows a pattern of up to 60 characters.  It
counts a pattern split across lines under /x, so a long pattern has to
be built from qr// parts.  The two in Trog::Log::DBI were rewritten in
the change before this one.  The rest were in tests, and most of them
matched fixed text, with every space written as [ ] and every dot
escaped.  Each is a quoted string now, matched with \Q...\E, which
reads as the text that it expects.  The two ends of the content of a
page are each a qr// of their own.

ProhibitBuiltinHomonyms reported fifteen subs, under five names, and
each name is an interface somebody else calls.  read, write and delete
are methods of every data model.  index is the route that every page
ends in, and a theme's routes call it by that name.  shutdown is a
method of Sys::Virt::Domain, which a test fakes.  So allow names those
five.

To make sure that a \Q pattern still fails when the text differs, I
changed one expected string in each of two tests.  Each test failed,
and I put each string back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
troglodyne-bot преди 6 дни
родител
ревизия
95b7358b38
променени са 4 файла, в които са добавени 22 реда и са изтрити 12 реда
  1. 6 2
      .perlcriticrc
  2. 4 3
      t/Trog-Log-Syslog.t
  3. 9 5
      t/Trog-Routes-HTML-series-lifecycle.t
  4. 3 2
      t/bin-migrate.t

+ 6 - 2
.perlcriticrc

@@ -227,7 +227,7 @@ stop_words_file = .pod_stopwords
 # name on its own, so these are the parts.
 package_exemptions = main tcms login useradd blob css email html javascript json text
 [RegularExpressions::ProhibitCaptureWithoutTest]
-#[RegularExpressions::ProhibitComplexRegexes]
+[RegularExpressions::ProhibitComplexRegexes]
 [RegularExpressions::ProhibitEnumeratedClasses]
 [RegularExpressions::ProhibitFixedStringMatches]
 [RegularExpressions::ProhibitSingleCharAlternation]
@@ -236,7 +236,11 @@ package_exemptions = main tcms login useradd blob css email html javascript json
 [RegularExpressions::RequireDotMatchAnything]
 [RegularExpressions::RequireExtendedFormatting]
 [Subroutines::ProhibitAmpersandSigils]
-#[Subroutines::ProhibitBuiltinHomonyms]
+[Subroutines::ProhibitBuiltinHomonyms]
+# tCMS: read, write and delete are methods of every data model.  index is the
+# route that every page ends in, which a theme's routes call by that name.
+# shutdown is a method of Sys::Virt::Domain, which a test fakes.
+allow = read write delete index shutdown
 [Subroutines::ProhibitManyArgs]
 [Subroutines::ProhibitNestedSubs]
 [Subroutines::ProhibitReturnSort]

+ 4 - 3
t/Trog-Log-Syslog.t

@@ -37,9 +37,10 @@ subtest 'a line arrives as the syslog of this machine reads it' => sub {
     my $got = received();
 
     # daemon is facility 3 and info is severity 6, so the priority is 3*8+6.
-    like( $got, qr/^<30>/,                                                                                                                   'as daemon.info' );
-    like( $got, qr/\btcms\[$$\]:[ ]/,                                                                                                        'tagged with the program name and the pid' );
-    like( $got, qr/:[ ]2026-09-29T12:00:00Z[ ]\[INFO\]:[ ]RequestId[ ]x[ ]From[ ]192\.0\.2\.1[ ]\|nobody\|[ ]Failed[ ]login[ ]for[ ]user\z/, 'with the line that the file gets, and no newline' );
+    like( $got, qr/^<30>/,            'as daemon.info' );
+    like( $got, qr/\btcms\[$$\]:[ ]/, 'tagged with the program name and the pid' );
+    my $line = ': 2026-09-29T12:00:00Z [INFO]: RequestId x From 192.0.2.1 |nobody| Failed login for user';
+    like( $got, qr/\Q$line\E\z/, 'with the line that the file gets, and no newline' );
 };
 
 subtest 'each level keeps its severity' => sub {

+ 9 - 5
t/Trog-Routes-HTML-series-lifecycle.t

@@ -339,7 +339,9 @@ my sub post_count {
 # The rendered page is ~40KB and mostly JavaScript.  Show the content well.
 my sub kontent {
     my ($body) = @_;
-    my ($k)    = $body =~ m{<div[ ]id="kontent"[ ]class="kontained">(.*?)<div[ ]id="rightbar"}s;
+    state $from = qr{<div[ ]id="kontent"[ ]class="kontained">};
+    state $to   = qr{<div[ ]id="rightbar"};
+    my ($k) = $body =~ m{$from(.*?)$to}s;
     $k //= $body;
     $k =~ s/<script\b.*?<\/script>//gs;
     return length($k) > 2500 ? substr( $k, 0, 2500 ) . "\n...[truncated]" : $k;
@@ -1134,9 +1136,10 @@ subtest 'microblog' => sub {
 
     my $body = series_page( 'microblog', 'specmicroblog', $title, 1 ) or return;
 
-    like( $body, qr{href='https://example\.com/spec'[ ]>Spec[ ]Microblog[ ]Child</a>}, 'title links out to href' );
-    like( $body, qr{id="postData-\Q$child->{id}\E"},                                   'body block rendered' );
-    like( $body, qr/Spec[ ]microblog[ ]body\./,                                        'body text rendered' );
+    my $link = q{href='https://example.com/spec' >Spec Microblog Child</a>};
+    like( $body, qr{\Q$link\E},                      'title links out to href' );
+    like( $body, qr{id="postData-\Q$child->{id}\E"}, 'body block rendered' );
+    like( $body, qr/Spec[ ]microblog[ ]body\./,      'body text rendered' );
 };
 
 subtest 'file' => sub {
@@ -1199,7 +1202,8 @@ subtest 'presentation' => sub {
     my $body = series_page( 'presentation', 'specpresentation', $title, 1 ) or return;
 
     # Slides only render under nochrome; the series page just links to the deck.
-    like( $body, qr{<a[ ]href="/posts/\Q$child->{id}\E\?embed=1&nochrome=1">Click[ ]Here[ ]to[ ]view</a>}, 'deck link rendered' );
+    my $deck = qq{<a href="/posts/$child->{id}?embed=1&nochrome=1">Click Here to view</a>};
+    like( $body, qr{\Q$deck\E}, 'deck link rendered' );
     unlike( $body, qr/Slide[ ]one[ ]body\./, 'slides themselves are not rendered inline' );
 };
 

+ 3 - 2
t/bin-migrate.t

@@ -130,8 +130,9 @@ subtest 'a dry run writes nothing' => sub {
 subtest 'the migration itself' => sub {
     my ( $rc, $out ) = migrate();
     is( $rc, 0, 'it succeeds' ) or diag($out);
-    like( $out, qr/Carried[ ]over[ ]6[ ]post[ ]version\(s\),[ ]skipped[ ]0/,                                'carrying over every version' );
-    like( $out, qr/data\/files[ ]holds[ ]6[ ]post[ ]version\(s\);[ ]data\/posts\.sqlite[ ]now[ ]holds[ ]6/, 'and says what actually landed' );
+    like( $out, qr/Carried[ ]over[ ]6[ ]post[ ]version\(s\),[ ]skipped[ ]0/, 'carrying over every version' );
+    my $landed = 'data/files holds 6 post version(s); data/posts.sqlite now holds 6';
+    like( $out, qr/\Q$landed\E/, 'and says what actually landed' );
 
     is( $sqlite->count(), 4, 'four posts' );