1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
# frozen_string_literal: true
module PerfettoSnapshot
def check_snapshot(data, snapshot_name)
prev_file = caller(1, 1).first.sub(/\/[a-z_]*\.rb:.*/, "")
snapshot_dir = prev_file + "/snapshots"
snapshot_path = "#{snapshot_dir}/#{snapshot_name}"
iid_table = { "debugAnnotationNames" => {}, "eventNames" => {}, "eventCategories" => {}, "debugAnnotationStringValues" => {} }
build_intern_map(data, iid_table)
if ENV["UPDATE_PERFETTO"]
puts "Updating PerfettoTrace snapshot: #{snapshot_path.inspect}"
snapshot_json = convert_to_snapshot(data, iid_table)
FileUtils.mkdir_p(snapshot_dir)
File.write(snapshot_path, JSON.pretty_generate(snapshot_json))
elsif !File.exist?(snapshot_path)
raise "Snapshot file not found: #{snapshot_path.inspect}"
else
snapshot_data = JSON.parse(File.read(snapshot_path))
cleaned_data = convert_to_snapshot(data, iid_table)
deep_snap_match(snapshot_data, cleaned_data, [])
end
end
def deep_snap_match(snapshot_data, data, path)
case snapshot_data
when String
assert_kind_of String, data, "Is String at #{path.join(".")}"
if snapshot_data.match(/\D/).nil? && data.match(/\D/).nil?
# Ok
elsif BASE64_PATTERN.match?(snapshot_data)
snapshot_data_decoded = Base64.decode64(snapshot_data)
data_decoded = Base64.decode64(data)
assert_equal snapshot_data_decoded, data_decoded, "Decoded match at #{path.join(".")}"
else
assert_equal snapshot_data, data, "Match at #{path.join(".")}"
end
when Numeric
assert_kind_of Numeric, data, "Is numeric at #{path.join(".")}"
when Hash
assert_equal snapshot_data.class, data.class, "Match at #{path.join(".")}"
extra_keys = snapshot_data.keys - data.keys
extra_keys += data.keys - snapshot_data.keys
assert_equal snapshot_data.keys.sort, data.keys.sort, "Match at #{path.join(".")} (#{extra_keys.map { |k| "#{k.inspect} => #{data[k].inspect}, snapshot: #{snapshot_data[k].inspect}"}.join(", ")})"
snapshot_data.each do |k, v|
next_data = data[k]
if k == "debugAnnotations"
next_data.sort_by! { |d| d["name"] }
end
deep_snap_match(v, data[k], path + [k])
end
when Array
assert_equal(snapshot_data.class, data.class, "Match at #{path.join(".")}")
snapshot_data.each_with_index do |snapshot_i, idx|
data_i = data[idx]
deep_snap_match(snapshot_i, data_i, path + [idx])
end
end
end
BASE64_PATTERN = /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?\n?$/
def replace_ids(str)
str.gsub(/ #\d+/, " #1010").split(/:0x[0-9a-z]+/).first
end
def convert_to_snapshot(value, iid_table)
case value
when String
if value.match(/\D/).nil?
"10101010101010"
elsif BASE64_PATTERN.match?(value)
decoded_value = Base64.decode64(value)
decoded_value = replace_ids(decoded_value)
Base64.encode64(decoded_value)
else
replace_ids(value)
end
when Numeric
101010101010
when Array
value.map { |v| convert_to_snapshot(v, iid_table) }
when Hash
h2 = {}
value.each do |k, v|
case k
when "debugAnnotations"
v.each { |d|
if d.key?("nameIid")
d["name"] = iid_table["debugAnnotationNames"][d["nameIid"]]
end
if d.key?("stringValueIid")
d["stringValue"] = iid_table["debugAnnotationNames"][d["stringValueIid"]]
end
}
v = v.sort_by { |d| d["name"] }
when "categoryIids"
h2["categories"] = v.map { |ciid| iid_table["eventCategories"][ciid] }
when "trackEvent"
if v.key?("nameIid")
v["name"] = iid_table["eventNames"][v["nameIid"]]
end
end
h2[k] = convert_to_snapshot(v, iid_table)
end
h2
when true, false, nil
value
else
raise ArgumentError, "Unexpected JSON value: #{value}"
end
end
def build_intern_map(data, iid_table)
case data
when Hash
if (id = data["internedData"])
id.each do |id_type, entries|
type_table = iid_table.fetch(id_type)
entries.each do |entry|
type_table[entry["iid"]] = entry["name"] || (entry["str"] ? Base64.decode64(entry["str"]) : nil)
end
end
end
data.each do |k, v|
build_intern_map(v, iid_table)
end
when Array
data.each { |v| build_intern_map(v, iid_table) }
else
# Done
end
end
end
|