Home | History | Annotate | Download | only in htdocs
      1 # iExploder - Generates bad HTML files to perform QA for web browsers.
      2 # Developed for the Mozilla Foundation.
      3 #####################
      4 #
      5 # Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
      6 # 
      7 # This software is provided 'as-is', without any express or implied warranty.
      8 # In no event will the authors be held liable for any damages arising from the
      9 # use of this software.
     10 # 
     11 # Permission is granted to anyone to use this software for any purpose,
     12 # including commercial applications, and to alter it and redistribute it
     13 # freely, subject to the following restrictions:
     14 # 
     15 # 1. The origin of this software must not be misrepresented; you must not
     16 # claim that you wrote the original software. If you use this software in a
     17 # product, an acknowledgment in the product documentation would be appreciated
     18 # but is not required.
     19 # 
     20 # 2. Altered source versions must be plainly marked as such, and must not be
     21 # misrepresented as being the original software.
     22 # 
     23 # 3. This notice may not be removed or altered from any source distribution.
     24 
     25 $VERSION="1.3.2"
     26 
     27 class IExploder
     28     attr_accessor :test_num, :subtest_num, :lookup_mode, :random_mode, :url
     29     attr_accessor :offset, :lines, :stop_num
     30     
     31     def initialize(max_tags, max_attrs, max_props)
     32         @htmlMaxTags = max_tags
     33         @htmlMaxAttrs = max_attrs
     34         @cssMaxProps = max_props
     35         @mangledTagTotal = 0
     36         @stop_num = 0
     37     end
     38     
     39     def setRandomSeed
     40         if @test_num > 0
     41             srand(@test_num)
     42         else
     43             srand
     44         end
     45     end
     46     
     47     
     48     def readTagFiles
     49         # These if statements are so that mod_ruby doesn't have to reload the files
     50         # each time
     51         
     52         if (! @cssTags)
     53             @cssTags = readTagFile('cssproperties.in');
     54         end
     55         
     56         if (! @htmlTags)
     57             @htmlTags = readTagFile('htmltags.in');
     58         end
     59         if (! @htmlAttr)
     60             @htmlAttr = readTagFile('htmlattrs.in');
     61         end
     62         
     63         if (! @htmlValues)
     64             @htmlValues = readTagFile('htmlvalues.in');
     65         end
     66         
     67         if (! @cssValues)
     68             @cssValues = readTagFile('cssvalues.in');
     69         end
     70         
     71     end
     72     
     73     
     74     def readTagFile(filename)
     75         list = Array.new
     76         File.new(filename).readlines.each { |line|
     77             line.chop!
     78             
     79             # Don't include comments.
     80             if (line !~ /^# /) && (line.length > 0)
     81                 list << line
     82             end
     83         }
     84         return  list
     85     end
     86     
     87     # based on make_up_value, essentially.
     88     def inventValue
     89         value = rand(19);
     90         case value
     91         when 1..3 then return (@htmlValues[rand(@htmlValues.length)])
     92         when 4..5 then return (@htmlValues[rand(@htmlValues.length)] + inventValue())
     93         when 6 then return (@htmlValues[rand(@htmlValues.length)] + "//" + inventValue())
     94         when 7 then return ''
     95             # this may return negative argument?
     96         when 8..10 then return rand(255).chr * (rand(256)+8)
     97         when 11 then return rand(255).chr * (rand(2048)+8)
     98         when 12 then return "#" + rand(999999).to_s
     99         when 13 then return rand(999999).to_s + "%"
    100         when 14..15 then return "&" + rand(999999).to_s + ";"
    101             # filters
    102         when 16 then
    103             return inventValue() + "=" + inventValue()
    104             
    105             # this my return undefined method + for nil:NilClass
    106         when 17 then return inventValue() + "," + inventValue()
    107         else
    108             if rand(5) > 3
    109                 return "-" + rand(999999).to_s
    110             else
    111                 return rand(999999).to_s
    112             end
    113         end
    114     end
    115     
    116     # based on make_up_value, essentially.
    117     def inventCssValue(tag)
    118         value = rand(23);
    119         case value
    120         when 1..10 then return @cssValues[rand(@cssValues.length)]
    121         when 11 then return ''
    122         when 12 then return rand(255).chr * (rand(8192)+8)
    123         when 13
    124             length = rand(1024) + 8
    125             return (rand(255).chr * length) + " " + (rand(255).chr * length) + " " + (rand(255).chr * length)
    126         when 14 then return (rand(255).chr * (rand(1024)+3)) + "px"
    127         when 15 then return (rand(255).chr * (rand(1024)+3)) + "em"
    128         when 16 then return "url(" + inventValue() + ")"
    129         when 17..18 then return "#" + rand(999999999).to_s
    130         when 19 then return "-" + rand(99999999).to_s
    131         else return rand(99999999).to_s;
    132         end
    133     end
    134     
    135     
    136     def mangleTag(tag)
    137         @mangledTagTotal += 1
    138         out = ''
    139         
    140         # 20% chance of closing a tag instead of opening it. This 
    141         # still counts against @mangledTagTotal, however.
    142         if rand(10) > 8
    143             out = "</" + tag + ">"
    144             return out
    145         end
    146         
    147         # we're opening it.
    148         out = "<" + tag
    149         
    150         # forgot the space between the tag and the attributes
    151         if rand(15) > 1
    152             out << ' '
    153         end
    154         
    155         attrNum = rand(@htmlMaxAttrs) + 1
    156         
    157         1.upto(attrNum) {
    158             attr = @htmlAttr[rand(@htmlAttr.length)]
    159             
    160             out << attr
    161             
    162             # 7.5% of the time we skip the = sign. Don't prefix it
    163             # if the attribute ends with a ( however.
    164             
    165             
    166             if rand(15) > 1
    167                 out << '='
    168             end
    169             
    170             # sometimes quote it, sometimes not. I doubt the importance
    171             # of this test, but mangleme-1.2 added it, and adding more
    172             # random-ness never hurt anything but time. I'll do it less often.
    173             quote = rand(2)
    174             if (quote > 1)
    175                 out << "\""
    176             end
    177             
    178             out << inventValue()
    179             
    180             # end the quote when you are done
    181             if (quote > 1)
    182                 out << "\" "
    183             end
    184             
    185             # 5% chance we skip the space at the end of the name
    186             if rand(20) > 1
    187                 out << ' '
    188             end
    189             
    190         }
    191         
    192         # CSS styles!
    193         if rand(4) > 1
    194             out << " style=\""
    195             1.upto(rand(@cssMaxProps)+1) {
    196                 out << @cssTags[rand(@cssTags.length)]
    197                 
    198                 # very small chance we let the tag run on.
    199                 if rand(50) > 1
    200                     out << ": "
    201                 end
    202                 
    203                 out << inventCssValue(tag)
    204                 # we almost always put the ; there.
    205                 if rand(50) > 1
    206                     out << '; '
    207                 end
    208             }
    209             out << "\""
    210         end
    211         
    212         out << ">\n"
    213         
    214         # support our local troops!
    215         if (@subtest_num > 0) && filterSubTest() 
    216             if tag =~ /html|body|head/
    217                 return '<' + tag + '>'
    218             else
    219                 return "<x-#@mangledTagTotal>\n"
    220             end
    221         else
    222             return out
    223         end    
    224     end
    225     #end
    226     
    227     def filterSubTest()
    228         result = 1
    229         if (@mangledTagTotal >= @offset) && (@mangledTagTotal < (@offset + @lines))
    230             result = nil
    231         end
    232         return result
    233     end
    234     
    235     def nextTestNum()
    236         if random_mode
    237             n = rand(99999999)
    238         else
    239             if @test_num
    240                 n = @test_num  + 1
    241             else
    242                 n = 1
    243             end
    244         end
    245         return n
    246     end
    247     
    248     # If we are at line 30 with 8 extra lines, there is no point to try line 31
    249     # with 8 lines as well.. skip back to 1 and bump up the line count.
    250     def nextSubTestNum()    
    251         if (@offset + @lines) > @htmlMaxTags
    252             nextNum = ((@lines * 2 -1)) * @htmlMaxTags
    253         else
    254             nextNum = @subtest_num + 1
    255         end      
    256         return nextNum
    257     end
    258     
    259     
    260     def buildPage
    261         if (! @test_num) || (@test_num < 1)
    262             @test_num = 1
    263         end
    264         next_num=nextTestNum()
    265         @lines = @subtest_num.div(@htmlMaxTags) + 1
    266         @offset = @subtest_num.modulo(@htmlMaxTags)
    267         
    268         # building the HTML
    269         bodyText = mangleTag('html')
    270         bodyText << "\n<head>\n"
    271         
    272         # Only do redirects if lookup=1 has not been specified.
    273         if (! @lookup_mode) && (@lines <= @htmlMaxTags) && (@stop_num != @test_num)
    274             newpage = @url + "?"
    275             if @subtest_num > 0
    276                 newpage << "test=" << @test_num.to_s << "&subtest=" << nextSubTestNum().to_s
    277             else
    278                 newpage << "test=" << next_num.to_s
    279             end
    280             
    281             if @random_mode
    282                 newpage << "&random=1"
    283             end
    284             
    285             if @stop_num > 0
    286                 newpage << "&stop=" << @stop_num.to_s
    287             end
    288             
    289             bodyText << "\t<META HTTP-EQUIV=\"Refresh\" content=\"0;URL=#{newpage}\">\n" 
    290             # use both techniques, because you never know how you might be corrupting yourself.
    291             bodyText << "\t<script language=\"javascript\">setTimeout('window.location=\"#{newpage}\"', 1000);</script>\n" 
    292         end
    293         
    294         bodyText << "\t" << mangleTag('meta')
    295         bodyText << "\t" <<  mangleTag('meta')
    296         bodyText << "\t" <<  mangleTag('link')
    297         
    298         bodyText << "\t<title>[#@test_num] iExploder #{$VERSION} - #{inventValue()}</title>\n"
    299         bodyText << "</head>\n\n"
    300         
    301         # What tags will we be messing with ######################
    302         tagList = [ 'body']
    303         
    304         # we already have 5 tags?
    305         1.upto(@htmlMaxTags - 5 ) { tagList << @htmlTags[rand(@htmlTags.length)] }
    306         
    307         tagList.each { |tag|
    308             bodyText << mangleTag(tag)
    309             bodyText << inventValue() + "\n"
    310         }
    311         bodyText << "</body>\n</html>"
    312     end
    313 end
    314 
    315 
    316 
    317 if $0 == __FILE__
    318     max=ARGV[0].to_i
    319     puts "testing #{max} tags"
    320     test = IExploder.new(max, 5, 5)
    321     test.readTagFiles()
    322     test.test_num=1
    323     test.subtest_num=1
    324     counter=0
    325     test.lines=0
    326 
    327     while test.lines < max
    328         test.lines = test.subtest_num.div(max) + 1
    329         test.offset = test.subtest_num.modulo(max)
    330         test.subtest_num=test.nextSubTestNum
    331         counter = counter + 1
    332 	puts "[#{counter}] subtest #{test.subtest_num} is #{test.lines} lines with #{test.offset} offset"
    333     end
    334 
    335     puts "for #{max} tests, you will have #{counter} iterations until #{test.subtest_num}"
    336 end
    337 
    338