From a8af037b9d909dd22443e49ed3b840e353d57dd9 Mon Sep 17 00:00:00 2001 From: gemshrine <113778529+gemshrine@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:43:07 +0300 Subject: [PATCH 1/2] #1400: avoid mutating time inputs --- lib/fbe/github_graph.rb | 6 +++--- lib/fbe/if_absent.rb | 2 +- lib/fbe/just_one.rb | 2 +- test/fbe/test_github_graph.rb | 37 +++++++++++++++++++++++++++++++++++ test/fbe/test_if_absent.rb | 9 +++++++++ test/fbe/test_just_one.rb | 9 +++++++++ 6 files changed, 60 insertions(+), 5 deletions(-) diff --git a/lib/fbe/github_graph.rb b/lib/fbe/github_graph.rb index 444b4cf0..84ee0c0c 100644 --- a/lib/fbe/github_graph.rb +++ b/lib/fbe/github_graph.rb @@ -341,7 +341,7 @@ def pull_requests_with_reviews(owner, name, since, cursor: nil) id number updatedAt - timelineItems(first: 1, itemTypes: [PULL_REQUEST_REVIEW], since: "#{since.utc.iso8601}") { + timelineItems(first: 1, itemTypes: [PULL_REQUEST_REVIEW], since: "#{since.getutc.iso8601}") { nodes { ... on PullRequestReview { id } } @@ -463,7 +463,7 @@ def total_commits_pushed(owner, name, since, till = Time.now) defaultBranchRef { target { ... on Commit { - history(#{after}first: 100, since: "#{since.utc.iso8601}", until: "#{till.utc.iso8601}") { + history(#{after}first: 100, since: "#{since.getutc.iso8601}", until: "#{till.getutc.iso8601}") { totalCount nodes { oid @@ -507,7 +507,7 @@ def total_commits_pushed(owner, name, since, till = Time.now) # @param [Time] till The datetime to # @return [Hash] A hash with total issues and pulls def total_issues_created(owner, name, since, till = Time.now) - window = "created:#{since.utc.iso8601}..#{till.utc.iso8601}" + window = "created:#{since.getutc.iso8601}..#{till.getutc.iso8601}" result = query( <<~GRAPHQL { diff --git a/lib/fbe/if_absent.rb b/lib/fbe/if_absent.rb index 0141b000..78423820 100644 --- a/lib/fbe/if_absent.rb +++ b/lib/fbe/if_absent.rb @@ -71,7 +71,7 @@ def Fbe.if_absent(fb: Fbe.fb, always: false) if v.is_a?(String) vv = "'#{vv.gsub('"', '\\\\"').gsub("'", "\\\\'")}'" elsif v.is_a?(Time) - vv = v.utc.iso8601 + vv = v.getutc.iso8601 end "(eq #{k} #{vv})" end.join(' ') diff --git a/lib/fbe/just_one.rb b/lib/fbe/just_one.rb index 9465834a..c2d5b711 100644 --- a/lib/fbe/just_one.rb +++ b/lib/fbe/just_one.rb @@ -56,7 +56,7 @@ def Fbe.just_one(fb: Fbe.fb) if v.is_a?(String) vv = "'#{vv.gsub('"', '\\\\"').gsub("'", "\\\\'")}'" elsif v.is_a?(Time) - vv = v.utc.iso8601 + vv = v.getutc.iso8601 end "(eq #{k} #{vv})" end.join(' ') diff --git a/test/fbe/test_github_graph.rb b/test/fbe/test_github_graph.rb index 62a2c570..81ab85a0 100644 --- a/test/fbe/test_github_graph.rb +++ b/test/fbe/test_github_graph.rb @@ -1058,4 +1058,41 @@ def test_fake_total_releases_published_dont_count_after_till h = graph.total_releases_published(owner, name, since, till: since + 60) assert_equal(1, h['releases'], "the fake counts releases published after the till moment, seed: #{seed}") end + + def test_time_arguments_keep_their_utc_offsets + since = Time.new(2026, 10, 4, 12, 0, 0, '+03:00') + till = Time.new(2026, 10, 5, 12, 0, 0, '+05:00') + graph = Fbe::Graph.new(token: 'test') + graph.define_singleton_method(:query) do |qry| + if qry.include?('pullRequests') + { + 'repository' => { + 'pullRequests' => { + 'nodes' => [], 'pageInfo' => { 'hasNextPage' => false, 'endCursor' => nil } + } + } + } + elsif qry.include?('history(') + { + 'repository' => { + 'defaultBranchRef' => { + 'target' => { + 'history' => { + 'nodes' => [], 'totalCount' => 0, + 'pageInfo' => { 'hasNextPage' => false, 'endCursor' => nil } + } + } + } + } + } + else + { 'issues' => { 'issueCount' => 0 }, 'pulls' => { 'issueCount' => 0 } } + end + end + graph.pull_requests_with_reviews('owner', 'repo', since) + graph.total_commits_pushed('owner', 'repo', since, till) + graph.total_issues_created('owner', 'repo', since, till) + assert_equal(10_800, since.utc_offset) + assert_equal(18_000, till.utc_offset) + end end diff --git a/test/fbe/test_if_absent.rb b/test/fbe/test_if_absent.rb index 08654c2a..86206958 100644 --- a/test/fbe/test_if_absent.rb +++ b/test/fbe/test_if_absent.rb @@ -78,6 +78,15 @@ def test_ignores_with_time assert_nil(n) end + def test_does_not_change_time_utc_offset + at = Time.new(2026, 10, 4, 12, 0, 0, '+03:00') + Fbe.if_absent(fb: Factbase.new) do |fact| + fact.what = 'meeting' + fact.when = at + end + assert_equal(10_800, at.utc_offset) + end + def test_injects fb = Factbase.new n = diff --git a/test/fbe/test_just_one.rb b/test/fbe/test_just_one.rb index 7aaac15a..d18e099d 100644 --- a/test/fbe/test_just_one.rb +++ b/test/fbe/test_just_one.rb @@ -27,6 +27,15 @@ def test_tells_apart_two_times_inside_one_second assert_equal(2, fb.size) end + def test_does_not_change_time_utc_offset + at = Time.new(2026, 10, 4, 12, 0, 0, '+03:00') + Fbe.just_one(fb: Factbase.new) do |fact| + fact.what = 'meeting' + fact.when = at + end + assert_equal(10_800, at.utc_offset) + end + def test_ignores fb = Factbase.new fb.insert.foo = 'hello dude' From 5423daaecbbf2cd21548a923d312ecadb7535326 Mon Sep 17 00:00:00 2001 From: gemshrine <113778529+gemshrine@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:52:08 +0300 Subject: [PATCH 2/2] test: isolate time formatting from insertion --- test/fbe/test_if_absent.rb | 6 +++++- test/fbe/test_just_one.rb | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/fbe/test_if_absent.rb b/test/fbe/test_if_absent.rb index 86206958..1205a681 100644 --- a/test/fbe/test_if_absent.rb +++ b/test/fbe/test_if_absent.rb @@ -79,8 +79,12 @@ def test_ignores_with_time end def test_does_not_change_time_utc_offset + fb = Factbase.new + stored = fb.insert + stored.what = 'meeting' + stored.when = Time.utc(2026, 10, 4, 9, 0, 0) at = Time.new(2026, 10, 4, 12, 0, 0, '+03:00') - Fbe.if_absent(fb: Factbase.new) do |fact| + Fbe.if_absent(fb:) do |fact| fact.what = 'meeting' fact.when = at end diff --git a/test/fbe/test_just_one.rb b/test/fbe/test_just_one.rb index d18e099d..214f8755 100644 --- a/test/fbe/test_just_one.rb +++ b/test/fbe/test_just_one.rb @@ -28,8 +28,12 @@ def test_tells_apart_two_times_inside_one_second end def test_does_not_change_time_utc_offset + fb = Factbase.new + stored = fb.insert + stored.what = 'meeting' + stored.when = Time.utc(2026, 10, 4, 9, 0, 0) at = Time.new(2026, 10, 4, 12, 0, 0, '+03:00') - Fbe.just_one(fb: Factbase.new) do |fact| + Fbe.just_one(fb:) do |fact| fact.what = 'meeting' fact.when = at end