c0fae12c6cb34ca57e30b2487e1aebe520ef14a4
[packages/precise/mcollective.git] / lib / mcollective / vendor / json / tools / fuzz.rb
1 require 'json'
2
3 require 'iconv'
4 ISO_8859_1_TO_UTF8 = Iconv.new('utf-8', 'iso-8859-15')
5 class ::String
6   def to_utf8
7     ISO_8859_1_TO_UTF8.iconv self
8   end
9 end
10
11 class Fuzzer
12   def initialize(n, freqs = {})
13     sum = freqs.inject(0.0) { |s, x| s + x.last }
14     freqs.each_key { |x| freqs[x] /= sum }
15     s = 0.0
16     freqs.each_key do |x|
17       freqs[x] = s .. (s + t = freqs[x])
18       s += t
19     end
20     @freqs = freqs
21     @n = n
22     @alpha = (0..0xff).to_a
23   end
24
25   def random_string
26     s = ''
27     30.times { s << @alpha[rand(@alpha.size)] }
28     s.to_utf8
29   end
30
31   def pick
32     r = rand
33     found = @freqs.find { |k, f| f.include? rand }
34     found && found.first
35   end
36
37   def make_pick
38     k = pick
39     case
40     when k == Hash, k == Array
41       k.new
42     when k == true, k == false, k == nil
43       k
44     when k == String
45       random_string
46     when k == Fixnum
47       rand(2 ** 30) - 2 ** 29
48     when k == Bignum
49       rand(2 ** 70) - 2 ** 69
50     end
51   end
52
53   def fuzz(current = nil)
54     if @n > 0
55       case current
56       when nil
57         @n -= 1
58         current = fuzz [ Hash, Array ][rand(2)].new
59       when Array
60         while @n > 0
61           @n -= 1
62           current << case p = make_pick
63           when Array, Hash
64             fuzz(p)
65           else
66             p
67           end
68         end
69       when Hash
70         while @n > 0
71           @n -= 1
72           current[random_string] = case p = make_pick
73           when Array, Hash
74             fuzz(p)
75           else
76             p
77           end
78         end
79       end
80     end
81     current
82   end
83 end
84
85 class MyState < JSON.state
86   WS = " \r\t\n"
87
88   def initialize
89     super(
90           :indent       => make_spaces,
91           :space        => make_spaces,
92           :space_before => make_spaces,
93           :object_nl    => make_spaces,
94           :array_nl     => make_spaces,
95           :max_nesting  => false
96          )
97   end
98
99   def make_spaces
100     s = ''
101     rand(1).times { s << WS[rand(WS.size)] }
102     s
103   end
104 end
105
106 n = (ARGV.shift || 500).to_i
107 loop do
108   fuzzer = Fuzzer.new(n,
109                       Hash => 25,
110                       Array => 25,
111                       String => 10,
112                       Fixnum => 10,
113                       Bignum => 10,
114                       nil => 5,
115                       true => 5,
116                       false => 5
117                      )
118   o1 = fuzzer.fuzz
119   json = JSON.generate o1, MyState.new
120   if $DEBUG
121     puts "-" * 80
122     puts json, json.size
123   else
124     puts json.size
125   end
126   begin
127     o2 = JSON.parse(json, :max_nesting => false)
128   rescue JSON::ParserError => e
129     puts "Caught #{e.class}: #{e.message}\n#{e.backtrace * "\n"}"
130     puts "o1 = #{o1.inspect}", "json = #{json}", "json_str = #{json.inspect}"
131     puts "locals = #{local_variables.inspect}"
132     exit
133   end
134   if o1 != o2
135     puts "mismatch", "o1 = #{o1.inspect}", "o2 = #{o2.inspect}",
136       "json = #{json}", "json_str = #{json.inspect}"
137     puts "locals = #{local_variables.inspect}"
138   end
139 end