summaryrefslogtreecommitdiff
path: root/tool/lib/launchable.rb
blob: 38f4fe92b3e1925cfeebdb45c35a11f79c9ff08c (plain)
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
# frozen_string_literal: true
require 'json'
require 'uri'

module Launchable
  ##
  # JsonStreamWriter writes a JSON file using a stream.
  # By utilizing a stream, we can minimize memory usage, especially for large files.
  class JsonStreamWriter
    def initialize(path)
      @file = File.open(path, "w")
      @file.write("{")
      @indent_level = 0
      @is_first_key_val = true
      @is_first_obj = true
      write_new_line
    end

    def write_object obj
      if @is_first_obj
        @is_first_obj = false
      else
        write_comma
        write_new_line
      end
      @indent_level += 1
      @file.write(to_json_str(obj))
      @indent_level -= 1
      @is_first_key_val = true
      # Occasionally, invalid JSON will be created as shown below, especially when `--repeat-count` is specified.
      # {
      #   "testPath": "file=test%2Ftest_timeout.rb&class=TestTimeout&testcase=test_allows_zero_seconds",
      #   "status": "TEST_PASSED",
      #   "duration": 2.7e-05,
      #   "createdAt": "2024-02-09 12:21:07 +0000",
      #   "stderr": null,
      #   "stdout": null
      # }: null <- here
      # },
      # To prevent this, IO#flush is called here.
      @file.flush
    end

    def write_array(key)
      @indent_level += 1
      @file.write(to_json_str(key))
      write_colon
      @file.write(" ", "[")
      write_new_line
    end

    def close
      return if @file.closed?
      close_array
      @indent_level -= 1
      write_new_line
      @file.write("}", "\n")
      @file.flush
      @file.close
    end

    private
    def to_json_str(obj)
      json = JSON.pretty_generate(obj)
      json.gsub(/^/, ' ' * (2 * @indent_level))
    end

    def write_indent
      @file.write(" " * 2 * @indent_level)
    end

    def write_new_line
      @file.write("\n")
    end

    def write_comma
      @file.write(',')
    end

    def write_colon
      @file.write(":")
    end

    def close_array
      write_new_line
      write_indent
      @file.write("]")
      @indent_level -= 1
    end
  end
end