~ubuntu-branches/ubuntu/maverick/conglomerate/maverick

« back to all changes in this revision

Viewing changes to src/cong-random-document.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel T Chen
  • Date: 2005-11-08 05:07:06 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051108050706-bcg60nwqf1z3w0d6
Tags: 0.9.1-1ubuntu1
* Resynchronise with Debian (Closes: #4397).
  - Thanks, Jordan Mantha.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * cong-random-document.c
 
3
 *
 
4
 * Plugin for testing service of various kinds.  Not really intended for end-users.
 
5
 *
 
6
 * Copyright (C) 2005 David Malcolm
 
7
 *
 
8
 * Conglomerate is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License as
 
10
 * published by the Free Software Foundation; either version 2 of the
 
11
 * License, or (at your option) any later version.
 
12
 *
 
13
 * Conglomerate is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 *
 
22
 * Authors: David Malcolm <david@davemalcolm.demon.co.uk>
 
23
 */
 
24
 
 
25
#include "global.h"
 
26
#include "cong-util.h"
 
27
#include "cong-app.h"
 
28
#include "cong-dispspec.h"
 
29
#include "cong-dispspec-element.h"
 
30
#include "cong-dispspec-registry.h"
 
31
#include "cong-dtd.h"
 
32
#include "cong-eel.h"
 
33
 
 
34
#define LOG_RANDOM1(x)       (g_message ((x)))
 
35
#define LOG_RANDOM2(x, a)    (g_message ((x), (a)))
 
36
#define LOG_RANDOM3(x, a, b) (g_message ((x), (a), (b)))
 
37
 
 
38
typedef struct RandomCreationInfo RandomCreationInfo;
 
39
struct RandomCreationInfo
 
40
{
 
41
        CongDispspec *dispspec;
 
42
        gboolean ensure_valid;
 
43
        int depth;
 
44
        GRand *random;
 
45
};
 
46
 
 
47
static void
 
48
populate_element (RandomCreationInfo *rci,
 
49
                  xmlDocPtr xml_doc,
 
50
                  xmlNodePtr xml_node,
 
51
                  int depth);
 
52
 
 
53
/**
 
54
 * generate_bool_for_opt:
 
55
 * @rci:
 
56
 *
 
57
 * TODO: Write me
 
58
 */
 
59
static gboolean
 
60
generate_bool_for_opt (RandomCreationInfo *rci)
 
61
{
 
62
        g_assert (rci);
 
63
 
 
64
        return g_rand_boolean (rci->random);
 
65
}
 
66
 
 
67
/**
 
68
 * generate_count_for_mult:
 
69
 * @rci:
 
70
 *
 
71
 * TODO: Write me
 
72
 */
 
73
static gint
 
74
generate_count_for_mult (RandomCreationInfo *rci)
 
75
{
 
76
        g_assert (rci);
 
77
 
 
78
        return g_rand_int_range (rci->random,
 
79
                                 0,
 
80
                                 6);
 
81
}
 
82
 
 
83
/**
 
84
 * generate_count_for_plus:
 
85
 * @rci:
 
86
 *
 
87
 * TODO: Write me
 
88
 */
 
89
static gint
 
90
generate_count_for_plus (RandomCreationInfo *rci)
 
91
{
 
92
        g_assert (rci);
 
93
 
 
94
        return g_rand_int_range (rci->random,
 
95
                                 1,
 
96
                                 7);
 
97
}
 
98
 
 
99
/**
 
100
 * generate_count_for_ocur:
 
101
 * @rci:
 
102
 * @ocur:
 
103
 *
 
104
 * TODO: Write me
 
105
 */
 
106
static gint
 
107
generate_count_for_ocur (RandomCreationInfo *rci,
 
108
                         xmlElementContentOccur ocur)
 
109
{
 
110
        g_assert (rci);
 
111
 
 
112
        switch (ocur) {
 
113
        default: g_assert_not_reached ();
 
114
        case XML_ELEMENT_CONTENT_ONCE:
 
115
                return 1;
 
116
 
 
117
        case XML_ELEMENT_CONTENT_OPT:
 
118
                return generate_bool_for_opt (rci)?1:0;
 
119
 
 
120
        case XML_ELEMENT_CONTENT_MULT:
 
121
                return generate_count_for_mult (rci);
 
122
 
 
123
        case XML_ELEMENT_CONTENT_PLUS:
 
124
                return generate_count_for_plus (rci);
 
125
        }
 
126
        
 
127
}
 
128
 
 
129
#if 0
 
130
gchar*
 
131
cong_dtd_generate_source_for_content (xmlElementContentPtr content)
 
132
{
 
133
        g_return_val_if_fail (content, NULL);
 
134
 
 
135
        switch (ocur) {
 
136
        default: g_assert_not_reached ();
 
137
        case XML_ELEMENT_CONTENT_ONCE:
 
138
                return 1;
 
139
 
 
140
        case XML_ELEMENT_CONTENT_OPT:
 
141
                return generate_bool_for_opt (rci)?1:0;
 
142
 
 
143
        case XML_ELEMENT_CONTENT_MULT:
 
144
                return generate_count_for_mult (rci);
 
145
 
 
146
        case XML_ELEMENT_CONTENT_PLUS:
 
147
                return generate_count_for_plus (rci);
 
148
        }
 
149
        
 
150
}
 
151
#endif
 
152
 
 
153
/**
 
154
 * random_unichar:
 
155
 * @rci:
 
156
 *
 
157
 * TODO: Write me
 
158
 */
 
159
static gunichar
 
160
random_unichar (RandomCreationInfo *rci)
 
161
{
 
162
        /* FIXME: probably should have a smarter system... */
 
163
        gunichar result;
 
164
 
 
165
        /* Have a high chance of spaces, to create word-breaking opportunities: */
 
166
        if (0==g_rand_int_range (rci->random, 0, 10)) {
 
167
                return ' ';
 
168
        }
 
169
        
 
170
        while (1) {
 
171
                result = g_rand_int_range (rci->random, 1, 65535);
 
172
 
 
173
                if (g_unichar_isdefined (result)) {
 
174
                        if (!g_unichar_iscntrl (result)) {
 
175
 
 
176
#define UNICODE_VALID(Char)                   \
 
177
    ((Char) < 0x110000 &&                     \
 
178
     (((Char) & 0xFFFFF800) != 0xD800) &&     \
 
179
     ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
 
180
     ((Char) & 0xFFFE) != 0xFFFE)
 
181
 
 
182
                                if (UNICODE_VALID (result)) {
 
183
                                        return result;
 
184
                                }
 
185
                        }
 
186
                }
 
187
        }
 
188
}
 
189
 
 
190
/**
 
191
 * random_text:
 
192
 * @rci:
 
193
 *
 
194
 * TODO: Write me
 
195
 */
 
196
static gchar*
 
197
random_text (RandomCreationInfo *rci)
 
198
{
 
199
        /* FIXME: should we translate the various strings in this function? */
 
200
        switch (g_rand_int_range (rci->random, 0, 3)) {
 
201
        default: g_assert_not_reached ();
 
202
        case 0:
 
203
                return g_strdup ("the quick brown fox jumps over the lazy dog");
 
204
 
 
205
        case 1:
 
206
                return g_strdup ("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
 
207
 
 
208
        case 2:
 
209
                /* Generate an entirely random unicode string: */
 
210
                {
 
211
                        #define MAX_LENGTH (50)
 
212
                        gint count = g_rand_int_range (rci->random, 1, MAX_LENGTH);
 
213
                        gint i;
 
214
                        gunichar tmp_str[MAX_LENGTH+1];
 
215
                        gchar *utf8_text;
 
216
 
 
217
                        for (i=0;i<count;i++) {
 
218
                                tmp_str[i]= random_unichar (rci);
 
219
                        }
 
220
                        tmp_str[i]=0;
 
221
 
 
222
                        utf8_text = g_ucs4_to_utf8 (tmp_str,
 
223
                                                    count,
 
224
                                                    NULL,
 
225
                                                    NULL,
 
226
                                                    NULL);
 
227
 
 
228
                        if (g_utf8_validate (utf8_text, -1, NULL)) {
 
229
                                return utf8_text;
 
230
                        } else {
 
231
                                g_free (utf8_text);
 
232
                                return g_strdup ("fubar");
 
233
                        }
 
234
 
 
235
                }
 
236
        }
 
237
}
 
238
 
 
239
static void
 
240
populate_element_from_content (RandomCreationInfo *rci,
 
241
                               xmlDocPtr xml_doc,
 
242
                               xmlNodePtr xml_node,
 
243
                               int depth,
 
244
                               xmlElementContentPtr content)
 
245
{
 
246
        gint i;
 
247
        guint count;
 
248
 
 
249
        g_assert (content);
 
250
 
 
251
        count = generate_count_for_ocur (rci, content->ocur);
 
252
        
 
253
#if 0
 
254
        {
 
255
                gchar *frag = cong_dtd_generate_source_for_content (content);
 
256
                g_message ("got count of %i for %s", count, frag);
 
257
                g_free (frag);
 
258
        }
 
259
#endif
 
260
 
 
261
        for (i=0;i<count;i++) { 
 
262
                switch (content->type) {
 
263
                default: g_assert_not_reached ();
 
264
                case XML_ELEMENT_CONTENT_PCDATA:
 
265
                        {
 
266
                                gchar *text = random_text (rci);
 
267
                                xmlNodePtr child_node = xmlNewDocText (xml_doc,
 
268
                                                                       (const xmlChar*)text);
 
269
                                g_free (text);
 
270
 
 
271
                                xmlAddChild (xml_node, 
 
272
                                             child_node);
 
273
                        }
 
274
                        break;
 
275
                case XML_ELEMENT_CONTENT_ELEMENT:
 
276
                        {
 
277
                                xmlNodePtr child_node = xmlNewDocNode (xml_doc,
 
278
                                                                       NULL,
 
279
                                                                       content->name,
 
280
                                                                       (const xmlChar*)""); /* FIXME: namespace? */
 
281
                                xmlAddChild (xml_node, 
 
282
                                             child_node);
 
283
                                populate_element (rci,
 
284
                                                  xml_doc,
 
285
                                                  child_node,
 
286
                                                  depth+1);
 
287
                        }
 
288
                        break;
 
289
                case XML_ELEMENT_CONTENT_SEQ:
 
290
                        /* Do both c1 and c2 in sequence: */
 
291
                        populate_element_from_content (rci,
 
292
                                                       xml_doc,
 
293
                                                       xml_node,
 
294
                                                       depth,
 
295
                                                       content->c1);
 
296
                        populate_element_from_content (rci,
 
297
                                                       xml_doc,
 
298
                                                       xml_node,
 
299
                                                       depth,
 
300
                                                       content->c2);
 
301
                        break;
 
302
                case XML_ELEMENT_CONTENT_OR:
 
303
                        /* Do one of c1 or c2: */
 
304
                        if (generate_bool_for_opt (rci)) {
 
305
                                populate_element_from_content (rci,
 
306
                                                               xml_doc,
 
307
                                                               xml_node,
 
308
                                                               depth,
 
309
                                                               content->c1);
 
310
                        } else {
 
311
                                populate_element_from_content (rci,
 
312
                                                               xml_doc,
 
313
                                                               xml_node,
 
314
                                                               depth,
 
315
                                                               content->c2);
 
316
                        }
 
317
                        break;
 
318
                }
 
319
        }
 
320
}
 
321
 
 
322
static void
 
323
populate_element_from_dtd (RandomCreationInfo *rci,
 
324
                           xmlDocPtr xml_doc,
 
325
                           xmlNodePtr xml_node,
 
326
                           int depth,
 
327
                           xmlElementPtr element)
 
328
{
 
329
        g_assert (rci);
 
330
        g_assert (xml_doc);
 
331
        g_assert (xml_node);
 
332
        g_assert (element);
 
333
 
 
334
        switch (element->etype) {
 
335
        default: g_assert_not_reached ();
 
336
        case XML_ELEMENT_TYPE_UNDEFINED:
 
337
        case XML_ELEMENT_TYPE_EMPTY:
 
338
                /* do nothing */
 
339
                break;
 
340
 
 
341
        case XML_ELEMENT_TYPE_ANY:
 
342
                break;
 
343
 
 
344
        case XML_ELEMENT_TYPE_MIXED:
 
345
                break;
 
346
 
 
347
        case XML_ELEMENT_TYPE_ELEMENT:
 
348
                break;
 
349
        }
 
350
 
 
351
        if (element->content) {
 
352
                populate_element_from_content (rci,
 
353
                                               xml_doc,
 
354
                                               xml_node,
 
355
                                               depth+1,
 
356
                                               element->content);
 
357
        }
 
358
 
 
359
 
 
360
 
 
361
        /* FIXME: set up attributes! */
 
362
}
 
363
 
 
364
static void
 
365
populate_element (RandomCreationInfo *rci,
 
366
                  xmlDocPtr xml_doc,
 
367
                  xmlNodePtr xml_node,
 
368
                  int depth)
 
369
{
 
370
        g_assert (rci);
 
371
        g_assert (xml_doc);
 
372
        g_assert (xml_node);
 
373
 
 
374
        LOG_RANDOM3 ("populate_element (below <%s>, %i)", xml_node->name, depth);
 
375
 
 
376
        /* Safety cutoffs */
 
377
        { 
 
378
                /* Stop if we've reached the maximum depth */
 
379
                if (depth>=rci->depth) {
 
380
                        return;
 
381
                }
 
382
        }
 
383
 
 
384
        if (xml_doc->extSubset) {
 
385
                xmlElementPtr element = cong_dtd_element_get_element_for_node (xml_doc->extSubset,
 
386
                                                                               xml_node);
 
387
                if (element) {
 
388
                        populate_element_from_dtd (rci,
 
389
                                                   xml_doc,
 
390
                                                   xml_node,
 
391
                                                   depth,
 
392
                                                   element);
 
393
                        return;
 
394
                }
 
395
        } 
 
396
 
 
397
        /* No DTD information was available for this node; randomly add content: */
 
398
        {
 
399
                gint child_count;
 
400
                gint i;
 
401
                
 
402
                /* Slow algorithm */
 
403
                guint num_elements = cong_dispspec_get_num_elements (rci->dispspec);
 
404
 
 
405
                child_count = g_rand_int_range (rci->random, 
 
406
                                                0,
 
407
                                                (rci->depth-depth));
 
408
 
 
409
                for (i=0;i<child_count;i++) {
 
410
                        CongDispspecElement* ds_element;
 
411
                        xmlNodePtr child_node;
 
412
 
 
413
                        ds_element = cong_dispspec_get_element (rci->dispspec,
 
414
                                                                g_rand_int_range (rci->random, 
 
415
                                                                                  0,
 
416
                                                                                  num_elements));
 
417
                        g_assert (ds_element);
 
418
 
 
419
                        child_node = xmlNewDocNode (xml_doc,
 
420
                                                    NULL,
 
421
                                                    (const xmlChar*)cong_dispspec_element_get_local_name (ds_element),
 
422
                                                    (const xmlChar*)"");
 
423
                        if (cong_dispspec_element_get_ns_uri (ds_element)) {
 
424
                                xmlNsPtr xml_ns = xmlNewNs (child_node, 
 
425
                                                            (const xmlChar*)cong_dispspec_element_get_ns_uri (ds_element),
 
426
                                                            NULL);
 
427
                                xmlSetNs (child_node, 
 
428
                                          xml_ns);      
 
429
                        }
 
430
 
 
431
                        xmlAddChild (xml_node,
 
432
                                     child_node);
 
433
                        
 
434
                        populate_element (rci,
 
435
                                          xml_doc,
 
436
                                          child_node,
 
437
                                          depth+1);
 
438
                }
 
439
        }
 
440
}
 
441
 
 
442
xmlDocPtr
 
443
cong_make_random_doc (CongDispspec *dispspec, 
 
444
                      gboolean ensure_valid,
 
445
                      int depth)
 
446
{
 
447
        RandomCreationInfo rci;
 
448
        xmlDocPtr xml_doc;
 
449
        xmlNodePtr root_node;
 
450
        const CongExternalDocumentModel* dtd_model;
 
451
        CongDispspecElement *ds_element_root;
 
452
        const gchar *root_element;
 
453
 
 
454
        g_return_val_if_fail (dispspec, NULL);
 
455
 
 
456
        rci.dispspec = dispspec;
 
457
        rci.ensure_valid = ensure_valid;
 
458
        rci.depth = depth;
 
459
        rci.random = g_rand_new ();
 
460
 
 
461
        ds_element_root = cong_dispspec_get_first_element (dispspec); /* FIXME */
 
462
        g_assert (ds_element_root);
 
463
 
 
464
        root_element = cong_dispspec_element_get_local_name (ds_element_root);
 
465
        g_assert (root_element);
 
466
 
 
467
        dtd_model = cong_dispspec_get_external_document_model (dispspec,
 
468
                                                               CONG_DOCUMENT_MODE_TYPE_DTD);
 
469
 
 
470
        xml_doc = xmlNewDoc ((const xmlChar*)"1.0");
 
471
 
 
472
        root_node = xmlNewDocNode (xml_doc,
 
473
                                   NULL, /* xmlNsPtr ns, */
 
474
                                   (const xmlChar*)root_element,
 
475
                                   NULL);
 
476
        if (cong_dispspec_element_get_ns_uri (ds_element_root)) {
 
477
                xmlNsPtr xml_ns = xmlNewNs (root_node, 
 
478
                                            (const xmlChar*)cong_dispspec_element_get_ns_uri (ds_element_root),
 
479
                                            NULL);
 
480
                xmlSetNs (root_node, 
 
481
                          xml_ns);      
 
482
        }
 
483
        xmlDocSetRootElement (xml_doc,
 
484
                              root_node);
 
485
 
 
486
        if (dtd_model) {
 
487
                cong_util_add_external_dtd (xml_doc, 
 
488
                                            root_element,
 
489
                                            cong_external_document_model_get_public_id (dtd_model),
 
490
                                            cong_external_document_model_get_system_id (dtd_model));
 
491
        }
 
492
        
 
493
        populate_element (&rci,
 
494
                          xml_doc,
 
495
                          root_node,
 
496
                          0);
 
497
        return xml_doc;
 
498
}
 
499