cURL / Mailing Lists / curl-library / Single Mail

curl-library

[PATCH 3/3] Add helper script convsrctest.pl to manipulate --libcurl tests.

From: Colin Hogben <curl_at_pythontech.co.uk>
Date: Thu, 23 Feb 2012 09:53:26 +0000

The intention is to take the output of curl's --libcurl option,
as exercised in test 14xx, and generate a corresponding test15xx
in which the generated code is compiled and run. This will verify
that the generated code behaves equivalently to the original
invocation of the curl command.

The script is not yet integrated into the configure / makefile
machinery.

---
 tests/convsrctest.pl |  255 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/getpart.pm     |    5 +
 2 files changed, 260 insertions(+), 0 deletions(-)
 create mode 100755 tests/convsrctest.pl
diff --git a/tests/convsrctest.pl b/tests/convsrctest.pl
new file mode 100755
index 0000000..ee44239
--- /dev/null
+++ b/tests/convsrctest.pl
@@ -0,0 +1,255 @@
+#!/usr/bin/env perl
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel_at_haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+#***************************************************************************
+
+#=======================================================================
+# Read a test definition which exercises curl's --libcurl option.
+# Generate either compilable source code for a new test tool,
+# or a new test definition which runs the tool and expects the
+# same output.
+# This should verify that the --libcurl code really does perform
+# the same actions as the original curl invocation.
+#-----------------------------------------------------------------------
+# The output of curl's --libcurl option differs in several ways from
+# the code needed to integrate with the test tool environment:
+# - #include "test.h"
+# - no call of curl_global_init & curl_global_cleanup
+# - main() function vs. test() function
+# - no checking of curl_easy_setopt calls vs. test_setopt wrapper
+# - handling of stdout
+# - variable names ret & hnd vs. res & curl
+# - URL as literal string vs. passed as argument
+#=======================================================================
+use strict;
+require "getpart.pm";
+
+# Boilerplate code for test tool
+my $head =
+'#include "test.h"
+#include "memdebug.h"
+
+int test(char *URL)
+{
+  CURLcode res;
+  CURL *curl;
+';
+# Other declarations from --libcurl come here
+# e.g. curl_slist
+my $init =
+'
+  if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+    fprintf(stderr, "curl_global_init() failed\n");
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  if ((curl = curl_easy_init()) == NULL) {
+    fprintf(stderr, "curl_easy_init() failed\n");
+    curl_global_cleanup();
+    return TEST_ERR_MAJOR_BAD;
+  }
+';
+# Option setting, perform and cleanup come here
+my $exit =
+'  curl_global_cleanup();
+
+  return (int)res;
+}
+';
+
+my $myname = leaf($0);
+sub usage {die "Usage: $myname -c|-test=num testfile\n";}
+
+sub main {
+    @ARGV == 2
+        or usage;
+    my($opt,$testfile) = @ARGV;
+
+    if(loadtest($testfile)) {
+        die "$myname: $testfile doesn't look like a test case\n";
+    }
+
+    my $comment = sprintf("DO NOT EDIT - generated from %s by %s",
+                          leaf($testfile), $myname);
+    if($opt eq '-c') {
+        generate_c($comment);
+    }
+    elsif(my($num) = $opt =~ /^-test=(\d+)$/) {
+        generate_test($comment, $num);
+    }
+    else {
+        usage;
+    }
+}
+
+sub generate_c {
+    my($comment) = @_;
+    # Fetch the generated code, which is the output file checked by
+    # the old test.
+    my @libcurl = getpart("verify", "file")
+        or die "$myname: no <verify><file> section found\n";
+
+    # Mangle the code into a suitable form for a test tool.
+    # We want to extract the important parts (declarations,
+    # URL, setopt calls, cleanup code) from the --libcurl
+    # boilerplate and insert them into a new boilerplate.
+    my(@decl,@code);
+    # First URL passed in as argument, others as global
+    my @urlvars = ('URL', 'libtest_arg2', 'libtest_arg3');
+    my($seen_main,$seen_setopt,$seen_return);
+    foreach (@libcurl) {
+        # Check state changes first (even though it
+        # duplicates some matches) so that the other tests
+        # are in a logical order).
+        if(/^int main/) {
+            $seen_main = 1;
+        }
+        if($seen_main and /curl_easy_setopt/) {
+            # Don't match 'curl_easy_setopt' in comment!
+            $seen_setopt = 1;
+        }
+        if(/^\s*return/) {
+            $seen_return = 1;
+        }
+
+        # Now filter the code according to purpose
+        if(! $seen_main) {
+            next;
+        }
+        elsif(! $seen_setopt) {
+            if(/^\s*(int main|\{|CURLcode |CURL |hnd = curl_easy_init)/) {
+                # Initialisations handled by boilerplate
+                next;
+            }
+            else {
+                push @decl, $_;
+            }
+        }
+        elsif(! $seen_return) {
+            if(/CURLOPT_URL/) {
+                # URL is passed in as argument or by global
+		my $var = shift @urlvars;
+                s/\"[^\"]*\"/$var/;
+            }
+	    s/\bhnd\b/curl/;
+            # Convert to macro wrapper
+            s/curl_easy_setopt/test_setopt/;
+	    if(/curl_easy_perform/) {
+		s/\bret\b/res/;
+		push @code, $_;
+		push @code, "test_cleanup:\n";
+	    }
+	    else {
+		push @code, $_;
+	    }
+        }
+    }
+
+    print ("/* $comment */\n",
+           $head,
+           @decl,
+           $init,
+           @code,
+           $exit);
+}
+
+# Read the original test data file and transform it
+# - add a "DO NOT EDIT comment"
+# - replace CURLOPT_URL string with URL variable
+# - remove <verify><file> section (was the --libcurl output)
+# - insert a <client><tool> section with our new C program name
+# - replace <client><command> section with the URL
+sub generate_test {
+    my($comment,$newnumber) = @_;
+    my @libcurl = getpart("verify", "file")
+        or die "$myname: no <verify><file> section found\n";
+    # Scan the --libcurl code to find the URL used.
+    my $url;
+    foreach (@libcurl) {
+        if(my($u) = /CURLOPT_URL, \"([^\"]*)\"/) {
+            $url = $u;
+        }
+    }
+    die "$myname: CURLOPT_URL not found\n"
+        unless defined $url;
+
+    # Traverse the pseudo-XML transforming as required
+    my @new;
+    my(@path,$path,$skip);
+    foreach (getall()) {
+        if(my($end) = /\s*<(\/?)testcase>/) {
+            push @new, $_;
+            push @new, "# $comment\n"
+                unless $end;
+        }
+        elsif(my($tag) = /^\s*<(\w+)/) {
+            push @path, $tag;
+            $path = join '/', @path;
+            if($path eq 'verify/file') {
+                $skip = 1;
+            }
+            push @new, $_
+                unless $skip;
+            if($path eq 'client') {
+                push @new, ("<tool>\n",
+                            "lib$newnumber\n",
+                            "</tool>\n");
+            }
+            elsif($path eq 'client/command') {
+                push @new, sh_quote($url)."\n";
+            }
+        }
+        elsif(my($etag) = /^\s*<\/(\w+)/) {
+            my $tag = pop @path;
+            die "$myname: mismatched </$etag>\n"
+                unless $tag eq $etag;
+            push @new, $_
+                unless $skip;
+            $skip --
+                if $path eq 'verify/file';
+            $path = join '/', @path;
+        }
+        else {
+            if($path eq 'client/command') {
+                # Replaced above
+            }
+            else {
+                push @new, $_
+                    unless $skip;
+            }
+        }
+    }
+    print @new;
+}
+
+sub leaf {
+    # Works for POSIX filenames
+    (my $path = shift) =~ s!.*/!!;
+    return $path;
+}
+
+sub sh_quote {
+    my $word = shift;
+    $word =~ s/[\$\"\'\\]/\\$&/g;
+    return '"' . $word . '"';
+}
+
+main;
diff --git a/tests/getpart.pm b/tests/getpart.pm
index 83e56ca..1aeedd6 100644
--- a/tests/getpart.pm
+++ b/tests/getpart.pm
@@ -124,6 +124,11 @@ sub getpart {
     return @this; #empty!
 }
 
+# Return entire document as list of lines
+sub getall {
+    return @xml;
+}
+
 sub loadtest {
     my ($file)=@_;
 
-- 
1.6.5.6
--------------060002010004040105020503
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
--------------060002010004040105020503--
Received on 2001-09-17