• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env perl
2#***************************************************************************
3#                                  _   _ ____  _
4#  Project                     ___| | | |  _ \| |
5#                             / __| | | | |_) | |
6#                            | (__| |_| |  _ <| |___
7#                             \___|\___/|_| \_\_____|
8#
9# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
10#
11# This software is licensed as described in the file COPYING, which
12# you should have received as part of this distribution. The terms
13# are also available at https://curl.se/docs/copyright.html.
14#
15# You may opt to use, copy, modify, merge, publish, distribute and/or sell
16# copies of the Software, and permit persons to whom the Software is
17# furnished to do so, under the terms of the COPYING file.
18#
19# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20# KIND, either express or implied.
21#
22# SPDX-License-Identifier: curl
23#
24#***************************************************************************
25
26#=======================================================================
27# Read a test definition which exercises curl's --libcurl option.
28# Generate either compilable source code for a new test tool,
29# or a new test definition which runs the tool and expects the
30# same output.
31# This should verify that the --libcurl code really does perform
32# the same actions as the original curl invocation.
33#-----------------------------------------------------------------------
34# The output of curl's --libcurl option differs in several ways from
35# the code needed to integrate with the test tool environment:
36# - #include "test.h"
37# - no call of curl_global_init & curl_global_cleanup
38# - main() function vs. test() function
39# - no checking of curl_easy_setopt calls vs. test_setopt wrapper
40# - handling of stdout
41# - variable names ret & hnd vs. res & curl
42# - URL as literal string vs. passed as argument
43#=======================================================================
44use strict;
45require "getpart.pm";
46
47# Boilerplate code for test tool
48my $head =
49'#include "test.h"
50#include "memdebug.h"
51
52int test(char *URL)
53{
54  CURLcode res;
55  CURL *curl;
56';
57# Other declarations from --libcurl come here
58# e.g. curl_slist
59my $init =
60'
61  if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
62    fprintf(stderr, "curl_global_init() failed\n");
63    return TEST_ERR_MAJOR_BAD;
64  }
65
66  if ((curl = curl_easy_init()) == NULL) {
67    fprintf(stderr, "curl_easy_init() failed\n");
68    curl_global_cleanup();
69    return TEST_ERR_MAJOR_BAD;
70  }
71';
72# Option setting, perform and cleanup come here
73my $exit =
74'  curl_global_cleanup();
75
76  return (int)res;
77}
78';
79
80my $myname = leaf($0);
81sub usage {die "Usage: $myname -c|-test=num testfile\n";}
82
83sub main {
84    @ARGV == 2
85        or usage;
86    my($opt,$testfile) = @ARGV;
87
88    if(loadtest($testfile)) {
89        die "$myname: $testfile doesn't look like a test case\n";
90    }
91
92    my $comment = sprintf("DO NOT EDIT - generated from %s by %s",
93                          leaf($testfile), $myname);
94    if($opt eq '-c') {
95        generate_c($comment);
96    }
97    elsif(my($num) = $opt =~ /^-test=(\d+)$/) {
98        generate_test($comment, $num);
99    }
100    else {
101        usage;
102    }
103}
104
105sub generate_c {
106    my($comment) = @_;
107    # Fetch the generated code, which is the output file checked by
108    # the old test.
109    my @libcurl = getpart("verify", "file")
110        or die "$myname: no <verify><file> section found\n";
111
112    # Mangle the code into a suitable form for a test tool.
113    # We want to extract the important parts (declarations,
114    # URL, setopt calls, cleanup code) from the --libcurl
115    # boilerplate and insert them into a new boilerplate.
116    my(@decl,@code);
117    # First URL passed in as argument, others as global
118    my @urlvars = ('URL', 'libtest_arg2', 'libtest_arg3');
119    my($seen_main,$seen_setopt,$seen_return);
120    foreach (@libcurl) {
121        # Check state changes first (even though it
122        # duplicates some matches) so that the other tests
123        # are in a logical order).
124        if(/^int main/) {
125            $seen_main = 1;
126        }
127        if($seen_main and /curl_easy_setopt/) {
128            # Don't match 'curl_easy_setopt' in comment!
129            $seen_setopt = 1;
130        }
131        if(/^\s*return/) {
132            $seen_return = 1;
133        }
134
135        # Now filter the code according to purpose
136        if(! $seen_main) {
137            next;
138        }
139        elsif(! $seen_setopt) {
140            if(/^\s*(int main|\{|CURLcode |CURL |hnd = curl_easy_init)/) {
141                # Initialization handled by boilerplate
142                next;
143            }
144            else {
145                push @decl, $_;
146            }
147        }
148        elsif(! $seen_return) {
149            if(/CURLOPT_URL/) {
150                # URL is passed in as argument or by global
151		my $var = shift @urlvars;
152                s/\"[^\"]*\"/$var/;
153            }
154	    s/\bhnd\b/curl/;
155            # Convert to macro wrapper
156            s/curl_easy_setopt/test_setopt/;
157	    if(/curl_easy_perform/) {
158		s/\bret\b/res/;
159		push @code, $_;
160		push @code, "test_cleanup:\n";
161	    }
162	    else {
163		push @code, $_;
164	    }
165        }
166    }
167
168    print ("/* $comment */\n",
169           $head,
170           @decl,
171           $init,
172           @code,
173           $exit);
174}
175
176# Read the original test data file and transform it
177# - add a "DO NOT EDIT comment"
178# - replace CURLOPT_URL string with URL variable
179# - remove <verify><file> section (was the --libcurl output)
180# - insert a <client><tool> section with our new C program name
181# - replace <client><command> section with the URL
182sub generate_test {
183    my($comment,$newnumber) = @_;
184    my @libcurl = getpart("verify", "file")
185        or die "$myname: no <verify><file> section found\n";
186    # Scan the --libcurl code to find the URL used.
187    my $url;
188    foreach (@libcurl) {
189        if(my($u) = /CURLOPT_URL, \"([^\"]*)\"/) {
190            $url = $u;
191        }
192    }
193    die "$myname: CURLOPT_URL not found\n"
194        unless defined $url;
195
196    # Traverse the pseudo-XML transforming as required
197    my @new;
198    my(@path,$path,$skip);
199    foreach (getall()) {
200        if(my($end) = /\s*<(\/?)testcase>/) {
201            push @new, $_;
202            push @new, "# $comment\n"
203                unless $end;
204        }
205        elsif(my($tag) = /^\s*<(\w+)/) {
206            push @path, $tag;
207            $path = join '/', @path;
208            if($path eq 'verify/file') {
209                $skip = 1;
210            }
211            push @new, $_
212                unless $skip;
213            if($path eq 'client') {
214                push @new, ("<tool>\n",
215                            "lib$newnumber\n",
216                            "</tool>\n");
217            }
218            elsif($path eq 'client/command') {
219                push @new, sh_quote($url)."\n";
220            }
221        }
222        elsif(my($etag) = /^\s*<\/(\w+)/) {
223            my $tag = pop @path;
224            die "$myname: mismatched </$etag>\n"
225                unless $tag eq $etag;
226            push @new, $_
227                unless $skip;
228            $skip --
229                if $path eq 'verify/file';
230            $path = join '/', @path;
231        }
232        else {
233            if($path eq 'client/command') {
234                # Replaced above
235            }
236            else {
237                push @new, $_
238                    unless $skip;
239            }
240        }
241    }
242    print @new;
243}
244
245sub leaf {
246    # Works for POSIX filenames
247    (my $path = shift) =~ s!.*/!!;
248    return $path;
249}
250
251sub sh_quote {
252    my $word = shift;
253    $word =~ s/[\$\"\'\\]/\\$&/g;
254    return '"' . $word . '"';
255}
256
257main;
258