source: branches/1.3/gui/apps/rpdiff @ 5667

Last change on this file since 5667 was 5667, checked in by ldelgass, 9 years ago

Merge r5662:5663 from trunk

  • Property svn:executable set to *
File size: 21.4 KB
Line 
1#!/bin/sh
2# ----------------------------------------------------------------------
3#  RPDIFF
4#
5#  Compares two Rappture run files and looks for differences in the
6#  output results.  This is useful for the BOINC integration and other
7#  job execution infrastructures, so we can compare the results from
8#  multiple runs.
9#
10#    USAGE:
11#    % rpdiff <runFile1> <runFile2>
12#
13#  Exits with status 0 if the files are the same, and non-zero status
14#  if the files are different.  Prints differences on stdout.  Prints
15#  any errors on stderr.
16# ======================================================================
17#  AUTHOR:  Michael McLennan, Purdue University
18#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
19#
20#  See the file "license.terms" for information on usage and
21#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22# ======================================================================
23# \
24exec tclsh "$0" ${1+"$@"}
25# tclsh executes the rest...
26package require Rappture
27
28# ----------------------------------------------------------------------
29# USAGE: diff <path> <lib1> <lib2>
30#
31# Used to compare two Rappture library objects at the specified <path>
32# in <lib1> and <lib2>.  Returns "" if they are the same, and a list
33# of differences if they are not.
34# ----------------------------------------------------------------------
35proc diff {path lib1 lib2} {
36    set knowntypes {boolean choice cloud curve field group histogram image integer loader log mesh note number periodicelement phase sequence string structure table unirect2d}
37    set type1 [$lib1 element -as type $path]
38    set type2 [$lib2 element -as type $path]
39    if {($type1 eq "" && $type2 ne "") || ($type1 ne "" && $type2 eq "")} {
40        return "missing component at $path"
41    } elseif {$type1 ne $type2} {
42        return "component mismatch at $path"
43    }
44
45    set diffs ""
46    switch -- $type1 {
47        input - output - group - phase {
48            set cpath1 [$lib1 children -as path $path]
49            set cpath2 [$lib2 children -as path $path]
50
51            # scan through all components in lib1 and diff against lib2
52            foreach cp $cpath1 {
53                set ct [$lib1 element -as type $cp]
54                if {[lsearch $knowntypes $ct] < 0} {
55                    # this isn't a real rappture object -- skip it
56                    set i [lsearch -exact $cpath2 $cp]
57                    if {$i >= 0} {
58                        set cpath2 [lreplace $cpath2 $i $i]
59                    }
60                    continue
61                }
62
63                set i [lsearch -exact $cpath2 $cp]
64                if {$i < 0} {
65                    lappend diffs "missing missing component at $cp"
66                } else {
67                    set cpath2 [lreplace $cpath2 $i $i]
68                    eval lappend diffs [diff $cp $lib1 $lib2]
69                }
70            }
71
72            # components left over that are in lib2 but not in lib1?
73            foreach cp $cpath2 {
74                lappend diffs "missing component at $cp"
75            }
76        }
77
78        boolean {
79            eval lappend diffs [diffattrs {
80                about.label about.description default
81            } $path $lib1 $lib2]
82
83            set v1 [$lib1 get $path.current]
84            if {$v1 ne "" && [catch {expr $v1} newval] == 0} { set v1 $newval }
85
86            set v2 [$lib2 get $path.current]
87            if {$v2 ne "" && [catch {expr $v2} newval] == 0} { set v2 $newval }
88
89            if {$v1 ne $v2} {
90                lappend diffs "value mismatch at $path.current"
91            }
92        }
93        choice {
94            eval lappend diffs [diffattrs {
95                about.label about.description default
96            } $path $lib1 $lib2]
97
98            set v1 [$lib1 get $path.current]
99            set v2 [$lib2 get $path.current]
100            if {$v1 ne $v2} {
101                lappend diffs "value mismatch at $path.current"
102            }
103        }
104        cloud {
105            eval lappend diffs [diffattrs {
106                about.label about.description units hide
107            } $path $lib1 $lib2]
108
109            eval lappend diffs [diffdatalines $path.points $lib1 $lib2]
110        }
111        curve {
112            eval lappend diffs [diffattrs {
113                about.label about.description
114                xaxis.label xaxis.description xaxis.units
115                yaxis.label yaxis.description yaxis.units
116            } $path $lib1 $lib2]
117
118            set cpath2 [$lib2 children -as path $path.component]
119            foreach elem [$lib1 children -as path $path.component] {
120                set i [lsearch -exact $cpath2 $elem]
121                if {$i >= 0} {
122                    set cpath2 [lreplace $cpath2 $i $i]
123                }
124
125                set data1 [$lib1 get $elem]
126                set data2 [$lib2 get $elem]
127                if {[llength $data1] != [llength $data2]} {
128                    lappend diffs "value mismatch at $elem"
129                    break
130                }
131
132                foreach d1 $data1 d2 $data2 {
133                    if {[Rappture::objects::ObjVal::cmpdbl $d1 $d2] != 0} {
134                        lappend diffs "value mismatch at $elem"
135                        break
136                    }
137                }
138            }
139            foreach elem $cpath2 {
140                # anything left in lib2 that's not in lib1?
141                lappend diffs "missing component at $elem"
142            }
143        }
144        field {
145            eval lappend diffs [diffattrs {
146                about.label about.description
147            } $path $lib1 $lib2]
148
149            set cpath2 [$lib2 children -as path -type component $path]
150            foreach elem [$lib1 children -as path -type component $path] {
151                set i [lsearch -exact $cpath2 $elem]
152                if {$i >= 0} {
153                    set cpath2 [lreplace $cpath2 $i $i]
154                }
155
156                # the flow attributes may or may not exist
157                eval lappend diffs [diffattrs {
158                    flow.label flow.description
159                } $elem $lib1 $lib2]
160
161                # must have the same dx (if defined)
162                set v1 [$lib1 get $elem.dx]
163                set v2 [$lib2 get $elem.dx]
164                if {$v1 ne $v2} {
165                    lappend diffs "value mismatch at $elem.dx"
166                    continue
167                }
168
169                # must have the same mesh
170                set v1 [$lib1 get $elem.mesh]
171                set v2 [$lib2 get $elem.mesh]
172                if {$v1 ne $v2} {
173                    lappend diffs "value mismatch at $elem.mesh"
174                    continue
175                }
176
177                # must have the same values
178                eval lappend diffs [diffdatalines $elem.values $lib1 $lib2]
179            }
180            foreach elem $cpath2 {
181                # anything left in lib2 that's not in lib1?
182                lappend diffs "missing component at $elem"
183            }
184        }
185        histogram {
186            eval lappend diffs [diffattrs {
187                about.label about.description
188                xaxis.label xaxis.description xaxis.units
189                yaxis.label yaxis.description yaxis.units
190            } $path $lib1 $lib2]
191
192            set cpath2 [$lib2 children -as path $path.component]
193            foreach elem [$lib1 children -as path $path.component] {
194                set i [lsearch -exact $cpath2 $elem]
195                if {$i >= 0} {
196                    set cpath2 [lreplace $cpath2 $i $i]
197                }
198
199                eval lappend diffs [diffdatalines $elem $lib1 $lib2]
200            }
201            foreach elem $cpath2 {
202                # anything left in lib2 that's not in lib1?
203                lappend diffs "missing component at $elem"
204            }
205        }
206        image {
207            eval lappend diffs [diffattrs {
208                about.label about.description resize convert
209            } $path $lib1 $lib2]
210
211            set v1 [$lib1 get $path.current]
212            set v2 [$lib2 get $path.current]
213            if {$v1 ne $v2} {
214                lappend diffs "value mismatch at $path.current"
215            }
216        }
217        integer {
218            eval lappend diffs [diffattrs {
219                about.label about.description min max default
220            } $path $lib1 $lib2]
221
222            set v1 [$lib1 get $path.current]
223            set v2 [$lib2 get $path.current]
224            if {[string is integer -strict $v1]
225                  && [string is integer -strict $v2]} {
226                if {$v1 != $v2} {
227                    lappend diffs "value mismatch at $path.current"
228                }
229            } elseif {$v1 ne $v2} {
230                lappend diffs "value mismatch at $path.current"
231            }
232        }
233        log {
234            set v1 [$lib1 get $path]
235            set v2 [$lib2 get $path]
236            if {$v1 ne $v2} {
237                lappend diffs "value mismatch at $path"
238            }
239        }
240        mesh {
241            eval lappend diffs [diffattrs {
242                about.label about.description units hide
243            } $path $lib1 $lib2]
244
245            # look for differences in nodes
246            set cpath2 [$lib2 children -as path -type node $path]
247            foreach elem [$lib1 children -as path -type node $path] {
248                set i [lsearch -exact $cpath2 $elem]
249                if {$i >= 0} {
250                    set cpath2 [lreplace $cpath2 $i $i]
251                }
252
253                eval lappend diffs [diffdatalines $elem $lib1 $lib2]
254            }
255            foreach elem $cpath2 {
256                # anything left in lib2 that's not in lib1?
257                lappend diffs "missing component at $elem"
258            }
259
260            # look for differences in elements
261            set cpath2 [$lib2 children -as path -type element $path]
262            foreach elem [$lib1 children -as path -type element $path] {
263                set i [lsearch -exact $cpath2 $elem]
264                if {$i >= 0} {
265                    set cpath2 [lreplace $cpath2 $i $i]
266                }
267
268                set v1 [$lib1 get $elem.node]
269                set v2 [$lib2 get $elem.node]
270                if {$v1 ne $v2} {
271                    lappend diffs "value mismatch at $path.node"
272                }
273            }
274            foreach elem $cpath2 {
275                # anything left in lib2 that's not in lib1?
276                lappend diffs "missing component at $elem"
277            }
278        }
279        note {
280            eval lappend diffs [diffattrs {contents} $path $lib1 $lib2]
281        }
282        number {
283            eval lappend diffs [diffattrs {
284                about.label about.description about.icon
285                min max units color default
286            } $path $lib1 $lib2]
287
288            set v1 [$lib1 get $path.current]
289            set v2 [$lib2 get $path.current]
290            if {[string is double -strict $v1]
291                  && [string is double -strict $v2]} {
292                if {[Rappture::objects::ObjVal::cmpdbl $v1 $v2] != 0} {
293                    lappend diffs "value mismatch at $path.current"
294                }
295            } elseif {$v1 ne $v2} {
296                lappend diffs "value mismatch at $path.current"
297            }
298        }
299        sequence {
300            eval lappend diffs [diffattrs {
301                about.label about.description index.label
302            } $path $lib1 $lib2]
303
304            set cpath2 [$lib2 children -as path -type element $path]
305            foreach elem [$lib1 children -as path -type element $path] {
306                set i [lsearch -exact $cpath2 $elem]
307                if {$i >= 0} {
308                    set cpath2 [lreplace $cpath2 $i $i]
309                }
310
311                # must have the same index
312                set v1 [$lib1 get $elem.index]
313                set v2 [$lib2 get $elem.index]
314                if {$v1 ne $v2} {
315                    lappend diffs "value mismatch at $elem.index"
316                    continue
317                }
318
319                # must have the same values
320                set parts1 [lsort [$lib1 children -as path $elem]]
321                set parts2 [lsort [$lib2 children -as path $elem]]
322                if {$parts1 ne $parts2} {
323                    lappend diffs "value mismatch at $elem"
324                    continue
325                }
326
327                foreach p $parts1 {
328                    set ptype [$lib1 element -as type $p]
329                    if {[lsearch $knowntypes $ptype] >= 0} {
330                        eval lappend diffs [diff $p $lib1 $lib2]
331                    }
332                }
333            }
334            foreach elem $cpath2 {
335                # anything left in lib2 that's not in lib1?
336                lappend diffs "missing component at $elem"
337            }
338        }
339        string {
340            eval lappend diffs [diffattrs {
341                about.label about.description default size hints
342            } $path $lib1 $lib2]
343
344            set v1 [$lib1 get $path.current]
345            set v2 [$lib2 get $path.current]
346            if {$v1 ne $v2} {
347                lappend diffs "value mismatch at $path.current"
348            }
349        }
350        structure {
351            eval lappend diffs [diffattrs {
352                about.label about.description
353            } $path $lib1 $lib2]
354
355            # check all parameters associated with the structure
356            set cpath2 [$lib2 children -as path $path.current.parameters]
357            foreach elem [$lib1 children -as path $path.current.parameters] {
358                set i [lsearch -exact $cpath2 $elem]
359                if {$i >= 0} {
360                    set cpath2 [lreplace $cpath2 $i $i]
361                }
362                eval lappend diffs [diff $elem $lib1 $lib2]
363            }
364            foreach elem $cpath2 {
365                # anything left in lib2 that's not in lib1?
366                lappend diffs "missing component at $elem"
367            }
368
369            # check all components in the structure
370            set cpath2 [$lib2 children -as path $path.current.components]
371            foreach elem [$lib1 children -as path $path.current.components] {
372                set i [lsearch -exact $cpath2 $elem]
373                if {$i >= 0} {
374                    set cpath2 [lreplace $cpath2 $i $i]
375                }
376
377                switch -- [$lib1 element -as type $elem] {
378                    box {
379                        eval lappend diffs [diffattrs {
380                            about.label about.color about.icon material
381                        } $elem $lib1 $lib2]
382
383                        set c2 [$lib2 children -as path -type corner $elem]
384                        foreach c [$lib1 children -as path -type corner $elem] {
385                            set i [lsearch -exact $c2 $c]
386                            if {$i >= 0} {
387                                set c2 [lreplace $c2 $i $i]
388                            }
389
390                            set v1 [$lib1 get $c]
391                            set v2 [$lib2 get $c]
392                            if {$v1 ne $v2} {
393                                lappend diffs "value mismatch at $c"
394                            }
395                        }
396                        foreach c $c2 {
397                            # anything left in lib2 that's not in lib1?
398                            lappend diffs "missing component at $c"
399                        }
400                    }
401                    molecule {
402                        eval lappend diffs [diffattrs {
403                            about.emblems formula
404                        } $elem $lib1 $lib2]
405
406                        # check for PDB data
407                        set v1 [$lib1 get $elem.pdb]
408                        set v2 [$lib2 get $elem.pdb]
409                        if {$v1 ne $v2} {
410                            lappend diffs "value mismatch at $elem.pdb"
411                        }
412
413                        # check for the old-style atom data
414                        set c2 [$lib2 children -as path -type atom $elem]
415                        foreach c [$lib1 children -as path -type atom $elem] {
416                            set i [lsearch -exact $c2 $c]
417                            if {$i >= 0} {
418                                set c2 [lreplace $c2 $i $i]
419                            }
420
421                            set v1 [$lib1 get $c.symbol]
422                            set v2 [$lib2 get $c.symbol]
423                            if {$v1 ne $v2} {
424                                lappend diffs "value mismatch at $c"
425                            }
426
427                            set df [diffdatalines $c.xyz $lib1 $lib2]
428                            if {$df ne ""} {
429                                eval lappend diffs $df
430                            }
431                        }
432                        foreach c $c2 {
433                            # anything left in lib2 that's not in lib1?
434                            lappend diffs "missing component at $c"
435                        }
436                    }
437                    default {
438                        error "don't know how to diff $elem"
439                    }
440                }
441            }
442            foreach elem $cpath2 {
443                # anything left in lib2 that's not in lib1?
444                lappend diffs "missing component at $elem"
445            }
446        }
447        table {
448            eval lappend diffs [diffattrs {
449                about.label about.description
450            } $path $lib1 $lib2]
451
452            set cpath2 [$lib2 children -as path -type column $path]
453            foreach elem [$lib1 children -as path -type column $path] {
454                set i [lsearch -exact $cpath2 $elem]
455                if {$i >= 0} {
456                    set cpath2 [lreplace $cpath2 $i $i]
457                }
458
459                eval lappend diffs [diffattrs {label units} $elem $lib1 $lib2]
460            }
461            foreach elem $cpath2 {
462                # anything left in lib2 that's not in lib1?
463                lappend diffs "missing component at $elem"
464            }
465
466            # make sure the table data matches
467            eval lappend diffs [diffdatalines $path.data $lib1 $lib2]
468        }
469        unirect2D {
470            eval lappend diffs [diffattrs {
471                about.label about.description hide
472                xaxis.label xaxis.units xaxis.numpoints
473                yaxis.label yaxis.units yaxis.numpoints
474            } $path $lib1 $lib2]
475
476            foreach elem {xaxis.min xaxis.max yaxis.min yaxis.max} {
477                set v1 [$lib1 get $path.$elem]
478                set v2 [$lib2 get $path.$elem]
479
480                if {[string is double -strict $v1]
481                      && [string is double -strict $v2]} {
482                    if {[Rappture::objects::ObjVal::cmpdbl $v1 $v2] != 0} {
483                        lappend diffs "value mismatch at $path.$elem"
484                    }
485                } elseif {$v1 ne $v2} {
486                    lappend diffs "value mismatch at $path.$elem"
487                }
488            }
489        }
490        loader {
491        }
492        default {
493            puts stderr "ignoring \"$type1\" for \"$path\""
494        }
495    }
496    return $diffs
497}
498
499# ----------------------------------------------------------------------
500# USAGE: diffattrs <attrList> <path> <lib1> <lib2>
501#
502# Used internally by the "diff" proc to look for a list of attributes
503# at the given <path> and see if there are any differences.  It is
504# considered a difference if the attribute is defined on one object
505# but not another, or if the string values are different.  Returns ""
506# if they are the same, and a list of differences if they are not.
507# ----------------------------------------------------------------------
508proc diffattrs {attrlist path lib1 lib2} {
509    set diffs ""
510    foreach name $attrlist {
511        set t1 [$lib1 element -as type $path.$name]
512        set t2 [$lib2 element -as type $path.$name]
513        if {$t1 ne "" || $t2 ne ""} {
514            if {[$lib1 get $path.$name] ne [$lib2 get $path.$name]} {
515                lappend diffs "attribute mismatch at $path.$name"
516            }
517        }
518    }
519    return $diffs
520}
521
522# ----------------------------------------------------------------------
523# USAGE: diffdatalines <path> <lib1> <lib2>
524#
525# Used internally by the "diff" proc to look for a list of attributes
526# at the given <path> and see if there are any differences.  It is
527# considered a difference if the attribute is defined on one object
528# but not another, or if the string values are different.  Returns ""
529# if they are the same, and a list of differences if they are not.
530# ----------------------------------------------------------------------
531proc diffdatalines {path lib1 lib2} {
532    set diffs ""
533
534    set data1 [split [string trim [$lib1 get $path]] \n]
535    set data2 [split [string trim [$lib2 get $path]] \n]
536    if {[llength $data1] != [llength $data2]} {
537        return [list "value mismatch at $path"]
538    }
539
540    foreach line1 $data1 line2 $data2 {
541        if {[llength $line1] != [llength $line2]} {
542            return [list "value mismatch at $path"]
543        }
544        foreach d1 $line1 d2 $line2 {
545            if {[string is double -strict $d1]
546                  && [string is double -strict $d2]} {
547                if {[Rappture::objects::ObjVal::cmpdbl $d1 $d2] != 0} {
548                    return [list "value mismatch at $path"]
549                }
550            } elseif {$d1 ne $d2} {
551                return [list "value mismatch at $path"]
552            }
553        }
554    }
555    return ""
556}
557
558# ======================================================================
559
560if {$argc < 2} {
561    puts stderr "USAGE: rpdiff file1.xml file2.xml"
562    exit 9
563}
564set lib1 [Rappture::library [lindex $argv 0]]
565set lib2 [Rappture::library [lindex $argv 1]]
566set path "output"
567if { $argc > 2 } {
568   set arg [lindex $argv 2]
569   if { $arg == "-path" && $argc == 4 } {
570      set path [lindex $argv 3]
571   }
572}
573
574# compute the differences
575set diffs [diff $path $lib1 $lib2]
576
577if {[llength $diffs] == 0} {
578    exit 0
579}
580
581# print a list of differences and exit
582foreach mesg $diffs {
583    puts $mesg
584}
585exit 1
Note: See TracBrowser for help on using the repository browser.