• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Origen-SDK / origen_testers / 27428703222

12 Jun 2026 04:26PM UTC coverage: 87.564% (-0.005%) from 87.569%
27428703222

push

github

priyavadan
Allow ROUNDTRIP_SOURCEMAP env override to force-enable the sidecar

The sourcemap gate normally reads site_config.roundtrip_sourcemap (off by
default). Also honor ENV['ROUNDTRIP_SOURCEMAP']=1 so a controlled regeneration
(e.g. the origen roundtrip command regenerating the original to diff against)
can force the sidecar on for that run without changing the site default.

3 of 4 new or added lines in 1 file covered. (75.0%)

13364 of 15262 relevant lines covered (87.56%)

6619.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.67
/lib/origen_testers/sourcemap.rb
1
require 'json'
4✔
2

3
module OrigenTesters
4✔
4
  # Round-trip provenance sidecar (tester-agnostic plumbing).
5
  #
6
  # Every tester renderer walks the same ATP AST, and every AST node already carries
7
  # provenance: a unique id, source file/line, the full flow-file lineage
8
  # (source_stack), and any domain provenance a plugin attached via options[:meta]
9
  # (the rt_* keys). This module collects that provenance as each output element is
10
  # rendered and writes it to a `<output_file>.sourcemap.json` sidecar.
11
  #
12
  # It is deliberately platform-neutral: it does NOT know what an SMT8 "suite", an
13
  # SMT7 test-instance, or an IGXL flow-row is. The renderer is responsible for the
14
  # one platform-specific thing -- the join KEY (the element's name as it appears in
15
  # that platform's output file) -- which it passes to record_sourcemap_entry. The
16
  # collection, meta extraction, append-merge, and file writing are all shared here.
17
  #
18
  # To enable for a tester:
19
  #   include OrigenTesters::Sourcemap
20
  #   - call record_sourcemap_entry(node, key, kind) from each on_* render hook
21
  #   - reset_sourcemap before the AST walk (e.g. in finalize)
22
  #   - call write_sourcemap_file after the output file is written (e.g. write_to_file)
23
  #
24
  # Purely additive: it only reads strings already on the AST nodes and writes an
25
  # extra file. It never changes the generated program output.
26
  module Sourcemap
4✔
27
    # Append a provenance record for a single rendered output element.
28
    #
29
    # @param node [OrigenTesters::ATP::AST::Node] the AST node being rendered
30
    # @param key [String] the element's name as it appears in the platform output
31
    #   file (the join key the reverse pass uses to match a diff back to source)
32
    # @param kind [String] element kind, e.g. 'test', 'sub_flow', 'auxiliary_flow'
33
    # @param test_method [Object, nil] the TML-aware test method, captured at RENDER
34
    #   time (the end-state right before the output is written, after all finalize and
35
    #   any user modification). Its parameter keys are the authoritative native tester
36
    #   parameter names + final rendered values for the loaded client/TML version.
37
    # Gate: the sourcemap is OFF by default and only emitted when a site enables it via
38
    # site_config (AMD turns it on internally; upstream/non-AMD users see no change and
39
    # pay no cost). Returns false unless Origen.site_config.roundtrip_sourcemap is truthy.
40
    def roundtrip_sourcemap_enabled?
4✔
41
      return @roundtrip_sourcemap_enabled unless @roundtrip_sourcemap_enabled.nil?
12,800✔
42
      @roundtrip_sourcemap_enabled = begin
43
        # ENV override lets a controlled in-process regeneration (e.g. the `origen
44
        # roundtrip` command regenerating the original to diff against) force the
45
        # sidecar on for that run, without depending on the site_config default.
46
        if %w(1 true).include?(ENV['ROUNDTRIP_SOURCEMAP'].to_s.downcase)
440✔
NEW
47
          true
×
48
        else
49
          v = Origen.site_config.respond_to?(:roundtrip_sourcemap) ? Origen.site_config.roundtrip_sourcemap : nil
440✔
50
          [true, 'true', 1, '1'].include?(v)
440✔
51
        end
52
      rescue StandardError
53
        false
×
54
      end
55
    end
56

57
    def record_sourcemap_entry(node, key, kind, test_method = nil)
4✔
58
      # When disabled, do no work at all -- skip the (potentially expensive) TML
59
      # format() collection entirely so there is zero render-time overhead.
60
      return unless roundtrip_sourcemap_enabled?
12,800✔
61
      @sourcemap ||= []
×
62
      entry = {
63
        # 'suite' retained as the key field name for backward compatibility with the
64
        # reverse tool; it holds whatever join key the platform supplied.
65
        'suite'        => key.to_s,
×
66
        'kind'         => kind,
67
        'node_id'      => (node.respond_to?(:id) ? node.id : nil),
×
68
        'source_file'  => (node.respond_to?(:file) ? node.file : nil),
×
69
        'source_line'  => (node.respond_to?(:line_number) ? node.line_number : nil),
×
70
        'source_stack' => (node.respond_to?(:source_stack) ? node.source_stack : nil)
×
71
      }
72
      prov = extract_meta_provenance(node)
×
73
      tml = extract_tml_params(test_method)
×
74
      entry['provenance'] = prov unless prov.empty?
×
75
      entry['tml_params'] = tml unless tml.empty?
×
76
      @sourcemap << entry
×
77
    end
78

79
    # Capture the FINAL native tester parameter names + values for this test, at render
80
    # time (the true end-state, after build + finalize + any user changes, immediately
81
    # before the param is written to the output file).
82
    #
83
    # The actual extraction is AMD/TML-specific knowledge (what a TML param is, how to
84
    # read its rendered value), so it is OWNED by amd_test_helpers and delegated to here
85
    # via the interface: if the loaded interface defines roundtrip_capture_tml_params,
86
    # we call it. This keeps origen_testers generic (no TML coupling) while still firing
87
    # at the correct render-time moment, which is the only point the live finalized
88
    # test_method is guaranteed reachable (SMT8 sub-flows render in forked processes, so
89
    # a later program-level callback cannot see these objects).
90
    def extract_tml_params(test_method)
4✔
91
      return {} unless test_method
×
92
      iface = (defined?(Origen) && Origen.respond_to?(:interface_loaded?) && Origen.interface_loaded?) ? Origen.interface : nil
×
93
      return {} unless iface && iface.respond_to?(:roundtrip_capture_tml_params)
×
94
      result = iface.roundtrip_capture_tml_params(test_method)
×
95
      result.is_a?(Hash) ? result : {}
×
96
    rescue StandardError
97
      {}
×
98
    end
99

100
    # Pull the rt_* (and any other) attributes out of the node's (meta ...) child.
101
    # Structure is: (meta (attribute "rt_burst" "value") (attribute "rt_mode" "x") ...)
102
    def extract_meta_provenance(node)
4✔
103
      result = {}
×
104
      return result unless node.respond_to?(:find)
×
105
      meta = node.find(:meta)
×
106
      return result unless meta
×
107
      meta.to_a.each do |attr|
×
108
        next unless attr.respond_to?(:type) && attr.type == :attribute
×
109
        k, v = *attr.to_a
×
110
        result[k.to_s] = v.to_s unless k.nil?
×
111
      end
112
      result
×
113
    end
114

115
    def sourcemap_entries
4✔
116
      @sourcemap ||= []
760✔
117
    end
118

119
    # Reset the accumulator. Call before each AST walk (finalize may run >once) so
120
    # re-rendering does not duplicate entries.
121
    def reset_sourcemap
4✔
122
      @sourcemap = []
972✔
123
    end
124

125
    # Where the sidecar is written: a hidden '.roundtrip/' subdirectory NEXT TO the
126
    # generated output file, named '<output-basename>.sourcemap.json'.
127
    #
128
    # The sourcemap is a DERIVED build artifact (regenerated from source every run) and
129
    # is large, so it must NOT be checked into revision control. Placing it under a
130
    # dedicated hidden dir keeps it out of the tester-facing output and makes it a single
131
    # trivially-gitignorable entry ('output/**/.roundtrip/'). The reverse tool reads it
132
    # from there for the run that produced the program; it is never committed.
133
    def sourcemap_output_file
4✔
134
      out = output_file
×
135
      base = out.basename(out.extname).to_s
×
136
      dir = out.dirname.join('.roundtrip')
×
137
      FileUtils.mkdir_p(dir.to_s) unless dir.exist?
×
138
      Pathname.new(dir.join("#{base}.sourcemap.json"))
×
139
    end
140

141
    def write_sourcemap_file
4✔
142
      return if sourcemap_entries.empty?
760✔
143
      return unless Origen.interface.respond_to?(:write?) ? Origen.interface.write? : true
×
144
      entries = sourcemap_entries
×
145
      # When several flow objects append to the same output file, each writes its own
146
      # portion; merge with whatever is already on disk so the sidecar stays in sync
147
      # with the appended output content.
148
      if @append && sourcemap_output_file.exist?
×
149
        begin
150
          existing = JSON.parse(File.read(sourcemap_output_file))
×
151
          entries = (existing['entries'] || []) + entries
×
152
        rescue StandardError
153
          # If the existing sidecar is unreadable, fall back to current entries only
154
        end
155
      end
156
      doc = {
157
        'version'      => 1,
×
158
        'flow'         => output_file.basename.to_s,
159
        'flow_path'    => output_file.to_s,
160
        'generated_by' => 'origen_testers roundtrip provenance',
161
        'entries'      => entries
162
      }
163
      File.open(sourcemap_output_file, 'w') { |f| f.puts JSON.pretty_generate(doc) }
×
164
      Origen.log.info "Writing... #{sourcemap_output_file.basename}"
×
165
    end
166
  end
167
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc