130 lines
5.3 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
Standardize valid strategy block return types Valid `strategy` block return types currently vary between strategies. Some only accept a string whereas others accept a string or array of strings. [`strategy` blocks also accept a `nil` return (to simplify early returns) but this was already standardized across strategies.] While some strategies only identify one version by default (where a string is an appropriate return type), it could be that a strategy block identifies more than one version. In this situation, the strategy would need to be modified to accept (and work with) an array from a `strategy` block. Rather than waiting for this to become a problem, this modifies all strategies to standardize on allowing `strategy` blocks to return a string or array of strings (even if only one of these is currently used in practice). Standardizing valid return types helps to further simplify the mental model for `strategy` blocks and reduce cognitive load. This commit extracts related logic from `#find_versions` into methods like `#versions_from_content`, which is conceptually similar to `PageMatch#page_matches` (renamed to `#versions_from_content` for consistency). This allows us to write tests for the related code without having to make network requests (or stub them) at this point. In general, this also helps to better align the structure of strategies and how the various `#find_versions` methods work with versions. There's still more planned work to be done here but this is a step in the right direction.
2021-08-10 11:09:55 -04:00
require "livecheck/strategy"
RSpec.describe Homebrew::Livecheck::Strategy::PageMatch do
subject(:page_match) { described_class }
let(:http_url) { "https://brew.sh/blog/" }
let(:non_http_url) { "ftp://brew.sh/" }
2020-12-22 22:46:52 -05:00
let(:regex) { %r{href=.*?/homebrew[._-]v?(\d+(?:\.\d+)+)/?["' >]}i }
let(:content) do
2020-12-22 22:46:52 -05:00
<<~EOS
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Homebrew Homebrew</title>
</head>
<body>
<ul class="posts">
<li><a href="/2020/12/01/homebrew-2.6.0/" title="2.6.0"><h2>2.6.0</h2><h3>01 Dec 2020</h3></a></li>
<li><a href="/2020/11/18/homebrew-tap-with-bottles-uploaded-to-github-releases/" title="Homebrew tap with bottles uploaded to GitHub Releases"><h2>Homebrew tap with bottles uploaded to GitHub Releases</h2><h3>18 Nov 2020</h3></a></li>
<li><a href="/2020/09/08/homebrew-2.5.0/" title="2.5.0"><h2>2.5.0</h2><h3>08 Sep 2020</h3></a></li>
<li><a href="/2020/06/11/homebrew-2.4.0/" title="2.4.0"><h2>2.4.0</h2><h3>11 Jun 2020</h3></a></li>
<li><a href="/2020/05/29/homebrew-2.3.0/" title="2.3.0"><h2>2.3.0</h2><h3>29 May 2020</h3></a></li>
<li><a href="/2019/11/27/homebrew-2.2.0/" title="2.2.0"><h2>2.2.0</h2><h3>27 Nov 2019</h3></a></li>
<li><a href="/2019/06/14/homebrew-maintainer-meeting/" title="Homebrew Maintainer Meeting"><h2>Homebrew Maintainer Meeting</h2><h3>14 Jun 2019</h3></a></li>
<li><a href="/2019/04/04/homebrew-2.1.0/" title="2.1.0"><h2>2.1.0</h2><h3>04 Apr 2019</h3></a></li>
<li><a href="/2019/02/02/homebrew-2.0.0/" title="2.0.0"><h2>2.0.0</h2><h3>02 Feb 2019</h3></a></li>
<li><a href="/2019/01/09/homebrew-1.9.0/" title="1.9.0"><h2>1.9.0</h2><h3>09 Jan 2019</h3></a></li>
</ul>
</body>
</html>
EOS
end
2020-12-23 09:12:53 -05:00
Standardize valid strategy block return types Valid `strategy` block return types currently vary between strategies. Some only accept a string whereas others accept a string or array of strings. [`strategy` blocks also accept a `nil` return (to simplify early returns) but this was already standardized across strategies.] While some strategies only identify one version by default (where a string is an appropriate return type), it could be that a strategy block identifies more than one version. In this situation, the strategy would need to be modified to accept (and work with) an array from a `strategy` block. Rather than waiting for this to become a problem, this modifies all strategies to standardize on allowing `strategy` blocks to return a string or array of strings (even if only one of these is currently used in practice). Standardizing valid return types helps to further simplify the mental model for `strategy` blocks and reduce cognitive load. This commit extracts related logic from `#find_versions` into methods like `#versions_from_content`, which is conceptually similar to `PageMatch#page_matches` (renamed to `#versions_from_content` for consistency). This allows us to write tests for the related code without having to make network requests (or stub them) at this point. In general, this also helps to better align the structure of strategies and how the various `#find_versions` methods work with versions. There's still more planned work to be done here but this is a step in the right direction.
2021-08-10 11:09:55 -04:00
let(:content_matches) { ["2.6.0", "2.5.0", "2.4.0", "2.3.0", "2.2.0", "2.1.0", "2.0.0", "1.9.0"] }
let(:find_versions_return_hash) do
2020-12-23 09:12:53 -05:00
{
matches: {
"2.6.0" => Version.new("2.6.0"),
"2.5.0" => Version.new("2.5.0"),
"2.4.0" => Version.new("2.4.0"),
"2.3.0" => Version.new("2.3.0"),
"2.2.0" => Version.new("2.2.0"),
"2.1.0" => Version.new("2.1.0"),
"2.0.0" => Version.new("2.0.0"),
"1.9.0" => Version.new("1.9.0"),
},
2024-03-07 16:20:20 +00:00
regex:,
url: http_url,
2020-12-23 09:12:53 -05:00
}
end
let(:find_versions_cached_return_hash) do
return_hash = find_versions_return_hash
return_hash[:cached] = true
return_hash
end
describe "::match?" do
it "returns true for an HTTP URL" do
expect(page_match.match?(http_url)).to be true
end
it "returns false for a non-HTTP URL" do
expect(page_match.match?(non_http_url)).to be false
end
end
2020-12-22 22:46:52 -05:00
Standardize valid strategy block return types Valid `strategy` block return types currently vary between strategies. Some only accept a string whereas others accept a string or array of strings. [`strategy` blocks also accept a `nil` return (to simplify early returns) but this was already standardized across strategies.] While some strategies only identify one version by default (where a string is an appropriate return type), it could be that a strategy block identifies more than one version. In this situation, the strategy would need to be modified to accept (and work with) an array from a `strategy` block. Rather than waiting for this to become a problem, this modifies all strategies to standardize on allowing `strategy` blocks to return a string or array of strings (even if only one of these is currently used in practice). Standardizing valid return types helps to further simplify the mental model for `strategy` blocks and reduce cognitive load. This commit extracts related logic from `#find_versions` into methods like `#versions_from_content`, which is conceptually similar to `PageMatch#page_matches` (renamed to `#versions_from_content` for consistency). This allows us to write tests for the related code without having to make network requests (or stub them) at this point. In general, this also helps to better align the structure of strategies and how the various `#find_versions` methods work with versions. There's still more planned work to be done here but this is a step in the right direction.
2021-08-10 11:09:55 -04:00
describe "::versions_from_content" do
it "returns an empty array if content is blank" do
expect(page_match.versions_from_content("", regex)).to eq([])
2020-12-22 22:46:52 -05:00
end
Standardize valid strategy block return types Valid `strategy` block return types currently vary between strategies. Some only accept a string whereas others accept a string or array of strings. [`strategy` blocks also accept a `nil` return (to simplify early returns) but this was already standardized across strategies.] While some strategies only identify one version by default (where a string is an appropriate return type), it could be that a strategy block identifies more than one version. In this situation, the strategy would need to be modified to accept (and work with) an array from a `strategy` block. Rather than waiting for this to become a problem, this modifies all strategies to standardize on allowing `strategy` blocks to return a string or array of strings (even if only one of these is currently used in practice). Standardizing valid return types helps to further simplify the mental model for `strategy` blocks and reduce cognitive load. This commit extracts related logic from `#find_versions` into methods like `#versions_from_content`, which is conceptually similar to `PageMatch#page_matches` (renamed to `#versions_from_content` for consistency). This allows us to write tests for the related code without having to make network requests (or stub them) at this point. In general, this also helps to better align the structure of strategies and how the various `#find_versions` methods work with versions. There's still more planned work to be done here but this is a step in the right direction.
2021-08-10 11:09:55 -04:00
it "returns an array of version strings when given content" do
expect(page_match.versions_from_content(content, regex)).to eq(content_matches)
# Regexes should use a capture group around the version but a regex
# without one should still be handled
expect(page_match.versions_from_content(content, /\d+(?:\.\d+)+/i)).to eq(content_matches)
end
it "returns an array of version strings when given content and a block" do
# Returning a string from block
expect(page_match.versions_from_content(content, regex) { "1.2.3" }).to eq(["1.2.3"])
# Returning an array of strings from block
expect(page_match.versions_from_content(content, regex) { |page, regex| page.scan(regex).map(&:first) })
.to eq(content_matches)
end
it "allows a nil return from a block" do
expect(page_match.versions_from_content(content, regex) { next }).to eq([])
2020-12-22 22:46:52 -05:00
end
Standardize valid strategy block return types Valid `strategy` block return types currently vary between strategies. Some only accept a string whereas others accept a string or array of strings. [`strategy` blocks also accept a `nil` return (to simplify early returns) but this was already standardized across strategies.] While some strategies only identify one version by default (where a string is an appropriate return type), it could be that a strategy block identifies more than one version. In this situation, the strategy would need to be modified to accept (and work with) an array from a `strategy` block. Rather than waiting for this to become a problem, this modifies all strategies to standardize on allowing `strategy` blocks to return a string or array of strings (even if only one of these is currently used in practice). Standardizing valid return types helps to further simplify the mental model for `strategy` blocks and reduce cognitive load. This commit extracts related logic from `#find_versions` into methods like `#versions_from_content`, which is conceptually similar to `PageMatch#page_matches` (renamed to `#versions_from_content` for consistency). This allows us to write tests for the related code without having to make network requests (or stub them) at this point. In general, this also helps to better align the structure of strategies and how the various `#find_versions` methods work with versions. There's still more planned work to be done here but this is a step in the right direction.
2021-08-10 11:09:55 -04:00
it "errors on an invalid return type from a block" do
expect { page_match.versions_from_content(content, regex) { 123 } }
.to raise_error(TypeError, Homebrew::Livecheck::Strategy::INVALID_BLOCK_RETURN_VALUE_MSG)
end
2020-12-22 22:46:52 -05:00
end
2020-12-23 09:12:53 -05:00
describe "::find_versions?" do
it "finds versions in provided_content" do
2024-03-07 16:20:20 +00:00
expect(page_match.find_versions(url: http_url, regex:, provided_content: content))
2021-04-04 03:00:34 +02:00
.to eq(find_versions_cached_return_hash)
2021-08-19 10:20:11 -04:00
# NOTE: Ideally, a regex should always be provided to `#find_versions`
# for `PageMatch` but there are currently some `livecheck` blocks in
# casks where `#regex` isn't used and the regex only exists within a
# `strategy` block. This isn't ideal but, for the moment, we allow a
# `strategy` block to act as a substitution for a regex and we need to
# test this scenario to ensure it works.
2021-08-19 10:20:11 -04:00
#
# Under normal circumstances, a regex should be established in a
# `livecheck` block using `#regex` and passed into the `strategy` block
# using `do |page, regex|`. Hopefully over time we can address related
# issues and get to a point where regexes are always established using
# `#regex`.
expect(page_match.find_versions(url: http_url, provided_content: content) do |page|
page.scan(%r{href=.*?/homebrew[._-]v?(\d+(?:\.\d+)+)/?["' >]}i).map(&:first)
end)
.to eq(find_versions_cached_return_hash.merge({ regex: nil }))
2020-12-23 09:12:53 -05:00
end
end
end