diff --git a/.rubocop.yml b/.rubocop.yml index 13a613f..9fcc3ba 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,46 +1,204 @@ +inherit_from: .rubocop_todo.yml + +# Last reviewed on Aug 31st 2023, using RuboCop v1.56.1 + +require: + - rubocop-rake + - rubocop-rspec + AllCops: - TargetRubyVersion: 2.7 NewCops: enable + TargetRubyVersion: 2.7 + +Style/FrozenStringLiteralComment: + Enabled: true + +Metrics/MethodLength: + Enabled: false +Metrics/PerceivedComplexity: + Max: 9 + +Metrics/CyclomaticComplexity: + Max: 9 + +# Our displays are wide enough. IDEs are configured to linebreak beautifully when needed :) we trust common sense here. +Layout/LineLength: + Enabled: false + +# Enforce that all string literals must use double quotes. This ensures real consistency. +# https://www.viget.com/articles/just-use-double-quoted-ruby-strings/ Style/StringLiterals: Enabled: true EnforcedStyle: double_quotes - Style/StringLiteralsInInterpolation: Enabled: true EnforcedStyle: double_quotes +# Multiline literals and method calls should always have a trailing comma as that makes diffs less noisy. +# https://medium.com/@nikgraf/why-you-should-enforce-dangling-commas-for-multiline-statements-d034c98e36f8 +Style/TrailingCommaInArrayLiteral: + Enabled: true + EnforcedStyleForMultiline: consistent_comma +Style/TrailingCommaInHashLiteral: + Enabled: true + EnforcedStyleForMultiline: consistent_comma Style/TrailingCommaInArguments: + Enabled: true + EnforcedStyleForMultiline: consistent_comma + +# Allows to write case/when/end statements like: +# long_variable_name = case x +# when "a" then 1 +# when "b" then 2 +# end +# Instead of having to indent it near the the case statement which looks weird. +Layout/CaseIndentation: + EnforcedStyle: end + IndentOneStep: true +Layout/EndAlignment: + EnforcedStyleAlignWith: start_of_line + +# The default style is `special_inside_parentheses` which looks like: +# +# this_is_a_method_call({ +# some_key: "value", +# }) +# +# This would cause an unnecessary huge diff if `in_a_method_call` is renamed, +# because all following lines need to be re-indented. That's why we prefer +# the layout like this: +# +# this_is_a_method_call({ +# some_key: "value", +# }) +# +Layout/FirstHashElementIndentation: + EnforcedStyle: consistent + +Layout/FirstArrayElementIndentation: + EnforcedStyle: consistent + +# Make sure gems are always alphabetically ordered. +Bundler/OrderedGems: + Enabled: true + +# Emojis are fun, guys. Let's use them! 🚀 (also, special characters such as "→" are way better than e.g. "->") +Style/AsciiComments: Enabled: false +# Lengthy blocks shouldn't be an issue in rspec… +Metrics/BlockLength: + Exclude: + - 'spec/**/*' + +# Prefer word array literals using %w[] syntax +# https://stackoverflow.com/a/1274703/4075379 Style/WordArray: Enabled: true EnforcedStyle: percent -Layout/LineLength: +# https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Next +Style/Next: + Enabled: true + EnforcedStyle: skip_modifier_ifs + +# https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/GuardClause +Style/GuardClause: + Enabled: true + +# Check for if and case statements where each branch is used for assignment to the same variable when using the return of the condition can be used instead. +Style/ConditionalAssignment: + Enabled: true + EnforcedStyle: assign_to_condition + +# Long positional parameter lists make it hard to reason about the code, but named arguments are easier to follow, so we allow them. +Metrics/ParameterLists: + CountKeywordArgs: false + +# We leave this one up to the developer's best judgement. For this to work well, we'd need to enable Layout/LineLength, +# which we don't want to because it would affect other areas of the codebase. +# https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/IfUnlessModifier +Style/IfUnlessModifier: Enabled: false -Style/FetchEnvVar: +# Aligning hash keys is important :) +# https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Layout/HashAlignment +Layout/HashAlignment: + Enabled: true + EnforcedHashRocketStyle: key + EnforcedColonStyle: key + EnforcedLastArgumentHashStyle: always_inspect + +# This extra empty line is not needed. +Layout/EmptyLineAfterGuardClause: Enabled: false -Metrics/PerceivedComplexity: - Max: 6 +# Ensures that each key, element, parameter, and argument in a multiline hash start on a separate line. +Layout/MultilineHashKeyLineBreaks: + Enabled: true +Layout/MultilineArrayLineBreaks: + Enabled: true +Layout/MultilineMethodParameterLineBreaks: + Enabled: true +Layout/MultilineMethodArgumentLineBreaks: + Enabled: true -Metrics/CyclomaticComplexity: - Max: 7 +# Ensures a line break before the first element in a multiline hash, array, parameter, and argument. +Layout/FirstHashElementLineBreak: + Enabled: true +Layout/FirstArrayElementLineBreak: + Enabled: true +Layout/FirstMethodParameterLineBreak: + Enabled: true +Layout/FirstMethodArgumentLineBreak: + Enabled: false # Except this one because sometimes it makes code more complex to read than it should be. -Metrics/BlockLength: - IgnoredMethods: - - 'describe' - - 'context' +# Helpful to make large numbers more readable. +Style/NumericLiterals: + Enabled: true + Exclude: + - 'db/schema.rb' # Don't format the magic date-like numbers generated by Rails. + +# Most of these are more complicated to read & write than simply writing the conventional way. +Style/SymbolArray: + Enabled: false + +Style/PerlBackrefs: + Enabled: false +# Omitting the hash value makes the code look too obscure. Not great for newcomers who are not used to this. +Style/HashSyntax: + Enabled: false + +# If it's redundant, let's get rid of the block as it's more noisy. +Style/RedundantFetchBlock: + Enabled: true + +# Use $stdout instead of STDOUT. +Style/GlobalStdStream: + Enabled: true + +# Prefer Api::V1::MyController instead of nested and indented modules +Style/ClassAndModuleChildren: + Enabled: false + +# This one measures "Assignment Branch Condition size". It's annoying and not helpful at all. Metrics/AbcSize: Enabled: false +# Don't enforce documentation. Trust common sense here. Style/Documentation: - Exclude: - - 'spec/**/*' - - 'test/**/*' + Enabled: false -Metrics/MethodLength: +RSpec/ExampleLength: + Enabled: false + +RSpec/MultipleExpectations: + Enabled: false + +RSpec/MultipleMemoizedHelpers: + Enabled: false + +RSpec/NestedGroups: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..1732df9 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,44 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2023-10-21 20:17:34 UTC using RuboCop version 1.53.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 24 +# Configuration parameters: . +# SupportedStyles: have_received, receive +RSpec/MessageSpies: + EnforcedStyle: receive + +# Offense count: 108 +# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. +# SupportedStyles: always, named_only +RSpec/NamedSubject: + Exclude: + - 'spec/config_parser_spec.rb' + - 'spec/dotenv_helper_spec.rb' + - 'spec/encoder_spec.rb' + - 'spec/helpers/string_spec.rb' + - 'spec/helpers/swift_template_helper_spec.rb' + - 'spec/models/arguments_spec.rb' + - 'spec/models/config_spec.rb' + - 'spec/models/secret_spec.rb' + - 'spec/models/template_arguments_spec.rb' + - 'spec/models/type_spec.rb' + - 'spec/salt_generator_spec.rb' + +# Offense count: 7 +RSpec/StubbedMock: + Exclude: + - 'spec/config_parser_spec.rb' + - 'spec/helpers/ui_spec.rb' + - 'spec/models/arguments_spec.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowedVars. +Style/FetchEnvVar: + Exclude: + - 'lib/arkana/encoder.rb' diff --git a/lib/arkana/helpers/swift_template_helper.rb b/lib/arkana/helpers/swift_template_helper.rb index 04af842..ec6113e 100644 --- a/lib/arkana/helpers/swift_template_helper.rb +++ b/lib/arkana/helpers/swift_template_helper.rb @@ -4,18 +4,18 @@ module SwiftTemplateHelper def self.swift_type(type) case type - when :string then "String" - when :boolean then "Bool" - when :integer then "Int" - else raise "Unknown variable type '#{type}' received.'" + when :string then "String" + when :boolean then "Bool" + when :integer then "Int" + else raise "Unknown variable type '#{type}' received.'" end end def self.protocol_getter(declaration_strategy) case declaration_strategy - when "lazy var" then "mutating get" - when "var", "let" then "get" - else raise "Unknown declaration strategy '#{declaration_strategy}' received.'" + when "lazy var" then "mutating get" + when "var", "let" then "get" + else raise "Unknown declaration strategy '#{declaration_strategy}' received.'" end end end diff --git a/lib/arkana/models/type.rb b/lib/arkana/models/type.rb index 0323b77..7aab27d 100644 --- a/lib/arkana/models/type.rb +++ b/lib/arkana/models/type.rb @@ -8,12 +8,12 @@ module Type def self.new(string_value:) case string_value - when "true", "false" - BOOLEAN - when /^\d+$/ - INTEGER - else - STRING + when "true", "false" + BOOLEAN + when /^\d+$/ + INTEGER + else + STRING end end end diff --git a/spec/arkana_spec.rb b/spec/arkana_spec.rb index d807779..3b96d4a 100644 --- a/spec/arkana_spec.rb +++ b/spec/arkana_spec.rb @@ -5,11 +5,12 @@ let(:config_filepath) { "spec/fixtures/arkana-fixture.yml" } let(:arguments) { Arguments.new } let(:config) { ConfigParser.parse(arguments) } + before { ARGV.replace(["--config-filepath", config_filepath]) } context "when one or more env vars are missing" do - it "should raise error" do - expect { Arkana.run(arguments) }.to raise_error(/Secret '(?:.*)' was declared but couldn't be found in the environment variables nor in the specified dotenv file./) + it "raises error" do + expect { described_class.run(arguments) }.to raise_error(/Secret '(?:.*)' was declared but couldn't be found in the environment variables nor in the specified dotenv file./) end end @@ -20,9 +21,9 @@ end end - it "should call SwiftCodeGenerator.generate" do + it "calls SwiftCodeGenerator.generate" do expect(SwiftCodeGenerator).to receive(:generate) - Arkana.run(arguments) + described_class.run(arguments) end end end diff --git a/spec/config_parser_spec.rb b/spec/config_parser_spec.rb index 99ae377..5845a20 100644 --- a/spec/config_parser_spec.rb +++ b/spec/config_parser_spec.rb @@ -1,38 +1,40 @@ # frozen_string_literal: true RSpec.describe ConfigParser do - subject { ConfigParser.parse(Arguments.new) } + subject { described_class.parse(Arguments.new) } describe "#parse" do before { ARGV.replace(["--config-filepath", "spec/fixtures/arkana-fixture.yml"]) } describe "when yaml file exists" do - it "should not fail" do - expect { ConfigParser.parse(Arguments.new) }.to_not raise_error + it "does not fail" do + expect { described_class.parse(Arguments.new) }.not_to raise_error end end describe "when yaml file doesn't exist" do let(:invalid_path) { "path/to/limbo" } + before { ARGV.replace(["--config-filepath", invalid_path]) } - it "should raise an error with user friendly message" do - expect { ConfigParser.parse(Arguments.new) }.to raise_error(/No such file or directory (?:.*) #{invalid_path}/) + it "raises an error with user friendly message" do + expect { described_class.parse(Arguments.new) }.to raise_error(/No such file or directory (?:.*) #{invalid_path}/) end end describe "#current_flavor" do describe "when flavor is specified in arguments" do let(:flavor) { "frootloops" } + before { ARGV << "--flavor" << flavor } - it "should be the same as the flavor specified" do + it "is the same as the flavor specified" do expect(subject.current_flavor).to eq flavor end end describe "when flavor is not specified in arguments" do - it "should be nil" do + it "is nil" do expect(subject.current_flavor).to be_nil end end @@ -42,21 +44,23 @@ context "when dotenv_filepath is specified" do context "when it exists" do let(:dotenv_filepath) { "spec/fixtures/dotenv.fixture" } + before { ARGV << "--dotenv-filepath" << dotenv_filepath } - it "should not log a warning and not raise an error" do - expect(UI).to_not receive(:warn) - expect { subject }.to_not raise_error + it "does not log a warning and not raise an error" do + expect(UI).not_to receive(:warn) + expect { subject }.not_to raise_error end end context "when it doesn't exist" do let(:dotenv_filepath) { "path/to/limbo" } + before { ARGV << "--dotenv-filepath" << dotenv_filepath } - it "should log a warning and not raise an error" do + it "logs a warning and not raise an error" do expect(UI).to receive(:warn).with("Dotenv file was specified but couldn't be found at '#{dotenv_filepath}'") - expect { subject }.to_not raise_error + expect { subject }.not_to raise_error end end end @@ -65,17 +69,17 @@ let(:default_fallback_dotenv_filepath) { ".env" } context "when a file exists at the default fallback dotenv filepath" do - it "should have dotenv_filepath equal to the default fallback dotenv filepath" do + it "has dotenv_filepath equal to the default fallback dotenv filepath" do expect(File).to receive(:exist?).with(default_fallback_dotenv_filepath).twice.and_return(true) - expect(UI).to_not receive(:warn) + expect(UI).not_to receive(:warn) expect(subject.dotenv_filepath).to eq default_fallback_dotenv_filepath end end context "when a file doesn't exist at the default fallback dotenv filepath" do - it "should have dotenv_filepath be nil" do + it "has dotenv_filepath be nil" do expect(File).to receive(:exist?).with(default_fallback_dotenv_filepath).and_return(false) - expect(UI).to_not receive(:warn) + expect(UI).not_to receive(:warn) expect(subject.dotenv_filepath).to be_nil end end diff --git a/spec/dotenv_helper_spec.rb b/spec/dotenv_helper_spec.rb index e25f675..74157d0 100644 --- a/spec/dotenv_helper_spec.rb +++ b/spec/dotenv_helper_spec.rb @@ -14,17 +14,17 @@ context "when current_flavor is not passed" do let(:current_flavor) { nil } - it "should load dotenv file from dotenv_filepath" do + it "loads dotenv file from dotenv_filepath" do expect(Dotenv).to receive(:load).with(dotenv_filepath).once - DotenvHelper.load(config) + described_class.load(config) end end context "when current_flavor is passed" do - it "should load dotenv files and flavor-specific env vars should override regular dotenv env vars" do + it "loads dotenv files and flavor-specific env vars should override regular dotenv env vars" do expect(Dotenv).to receive(:load).with(dotenv_filepath).once - expect(Dotenv).to receive(:load).with(DotenvHelper.flavor_dotenv_filepath(config)).once - DotenvHelper.load(config) + expect(Dotenv).to receive(:load).with(described_class.flavor_dotenv_filepath(config)).once + described_class.load(config) # NOTE: I couldn't make this work, not sure if it's possible: # expect(ENV["DOTENV_KEY"]).to eq "value from flavor dotenv" end @@ -32,13 +32,13 @@ end describe ".flavor_dotenv_filepath" do - subject { DotenvHelper.flavor_dotenv_filepath(config) } + subject { described_class.flavor_dotenv_filepath(config) } - it "should be in the same directory as the dotenv_filepath" do + it "is in the same directory as the dotenv_filepath" do expect(subject).to start_with("fixtures") end - it "should have a format of '.env.' followed by lowercased flavor" do + it "has a format of '.env.' followed by lowercased flavor" do expect(subject).to end_with("/.env.#{current_flavor.downcase}") end end diff --git a/spec/encoder_spec.rb b/spec/encoder_spec.rb index f88cc29..cb744a0 100644 --- a/spec/encoder_spec.rb +++ b/spec/encoder_spec.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true RSpec.describe Encoder do + subject { described_class.encode!(keys: keys, salt: salt, current_flavor: current_flavor, environments: environments) } + let(:salt) { SaltGenerator.generate } let(:environments) { [] } let(:current_flavor) { nil } - subject { Encoder.encode!(keys: keys, salt: salt, current_flavor: current_flavor, environments: environments) } describe ".encode!" do context "when keys is empty" do let(:keys) { [] } - it "should return empty array" do + it "returns empty array" do expect(subject.map(&:key)).to be_empty end end @@ -29,16 +30,16 @@ allow(ENV).to receive(:[]).with(existing_key2).and_return(existing_value2) end - it "should not raise error" do - expect { subject }.to_not raise_error + it "does not raise error" do + expect { subject }.not_to raise_error end - it "should return array with matching keys, values that are not the same as the stored value, and types" do + it "returns array with matching keys, values that are not the same as the stored value, and types" do expect(subject[0].key).to eq existing_key expect(subject[1].key).to eq existing_key2 - expect(subject[0].encoded_value).to_not eq existing_value - expect(subject[1].encoded_value).to_not eq existing_value2 + expect(subject[0].encoded_value).not_to eq existing_value + expect(subject[1].encoded_value).not_to eq existing_value2 expect(subject[0].type).to eq :string expect(subject[1].type).to eq :boolean @@ -54,7 +55,7 @@ allow(ENV).to receive(:[]).with(missing_key).and_return(nil) end - it "should raise error" do + it "raises error" do expect { subject }.to raise_error(/Secret '(?:.*)' was declared but couldn't be found in the environment variables nor in the specified dotenv file./) end end @@ -62,8 +63,9 @@ end describe "#find_secret!" do + subject { described_class.find_secret!(key: key, current_flavor: current_flavor) } + let(:key) { "LoremIpsum" } - subject { Encoder.find_secret!(key: key, current_flavor: current_flavor) } context "when current_flavor is passed" do let(:current_flavor) { "Ipsum" } @@ -71,9 +73,10 @@ context "when ENV contains the flavor-specific key" do let(:value) { "value" } + before { allow(ENV).to receive(:[]).with(flavor_key).and_return(value) } - it "should return the value from ENV" do + it "returns the value from ENV" do expect(subject).to eq value end end @@ -83,9 +86,10 @@ context "when ENV contains the key" do let(:value) { "value" } + before { allow(ENV).to receive(:[]).with(key).and_return(value) } - it "should return the value from ENV" do + it "returns the value from ENV" do expect(subject).to eq value end end @@ -93,7 +97,7 @@ context "when ENV doesn't contain the key" do before { allow(ENV).to receive(:[]).with(key).and_return(nil) } - it "should raise" do + it "raises" do expect { subject }.to raise_error(/Secret '#{flavor_key}' was declared but couldn't be found in the environment variables nor in the specified dotenv file./) end end @@ -105,9 +109,10 @@ context "when ENV contains the key" do let(:value) { "value" } + before { allow(ENV).to receive(:[]).with(key).and_return(value) } - it "should return the value from ENV" do + it "returns the value from ENV" do expect(subject).to eq value end end @@ -115,7 +120,7 @@ context "when ENV doesn't contain the key" do before { allow(ENV).to receive(:[]).with(key).and_return(nil) } - it "should raise" do + it "raises" do expect { subject }.to raise_error(/Secret '#{key}' was declared but couldn't be found in the environment variables nor in the specified dotenv file./) end end @@ -123,13 +128,14 @@ end describe "#protocol_key" do + subject { described_class.protocol_key(key: key, environments: environment ? [environment] : []) } + let(:key) { "LoremIpsum" } - subject { Encoder.protocol_key(key: key, environments: environment ? [environment] : []) } context "when the key passed has a suffix of one of the environments" do let(:environment) { "Ipsum" } - it "should return the key without the environment suffix" do + it "returns the key without the environment suffix" do expect(subject).to eq key.delete_suffix(environment) end end @@ -137,7 +143,7 @@ context "when the key passed doesn't have a suffix of one of the environments" do let(:environment) { "Dolor" } - it "should return the same key passed" do + it "returns the same key passed" do expect(subject).to eq key end end @@ -145,7 +151,7 @@ context "when no environments are passed" do let(:environment) { nil } - it "should return the same key passed" do + it "returns the same key passed" do expect(subject).to eq key end end diff --git a/spec/helpers/string_spec.rb b/spec/helpers/string_spec.rb index 3c9285b..d86cb11 100644 --- a/spec/helpers/string_spec.rb +++ b/spec/helpers/string_spec.rb @@ -4,7 +4,7 @@ describe "#camel_case" do subject { "FooBar" } - it "should lowercase the first letter" do + it "lowercases the first letter" do expect(subject.camel_case).to eq "fooBar" end end @@ -12,7 +12,7 @@ describe "#capitalize_first_letter" do subject { "fOOBaR" } - it "should capitalize the first letter and not change anything else in the rest of the string" do + it "capitalizes the first letter and not change anything else in the rest of the string" do expect(subject.capitalize_first_letter).to eq "FOOBaR" end end diff --git a/spec/helpers/swift_template_helper_spec.rb b/spec/helpers/swift_template_helper_spec.rb index f3a7db8..2d99a1a 100644 --- a/spec/helpers/swift_template_helper_spec.rb +++ b/spec/helpers/swift_template_helper_spec.rb @@ -4,12 +4,12 @@ RSpec.describe SwiftTemplateHelper do describe ".swift_type" do - subject { SwiftTemplateHelper.swift_type(type) } + subject { described_class.swift_type(type) } context "when type is :string" do let(:type) { :string } - it "should be Swift type String" do + it "is Swift type String" do expect(subject).to eq "String" end end @@ -17,7 +17,7 @@ context "when type is :boolean" do let(:type) { :boolean } - it "should be Swift type Bool" do + it "is Swift type Bool" do expect(subject).to eq "Bool" end end @@ -25,7 +25,7 @@ context "when type is :integer" do let(:type) { :integer } - it "should be Swift type Int" do + it "is Swift type Int" do expect(subject).to eq "Int" end end @@ -33,19 +33,19 @@ context "when type is unknown" do let(:type) { :bananas } - it "should raise error" do + it "raises error" do expect { subject }.to raise_error(/Unknown variable type '#{type}' received.'/) end end end describe ".protocol_getter" do - subject { SwiftTemplateHelper.protocol_getter(declaration_strategy) } + subject { described_class.protocol_getter(declaration_strategy) } context "when declaration strategy is 'var'" do let(:declaration_strategy) { "var" } - it "should return 'get'" do + it "returns 'get'" do expect(subject).to eq "get" end end @@ -53,7 +53,7 @@ context "when declaration strategy is 'let'" do let(:declaration_strategy) { "let" } - it "should return 'get'" do + it "returns 'get'" do expect(subject).to eq "get" end end @@ -61,7 +61,7 @@ context "when declaration strategy is 'lazy var'" do let(:declaration_strategy) { "lazy var" } - it "should return 'mutating get'" do + it "returns 'mutating get'" do expect(subject).to eq "mutating get" end end @@ -69,7 +69,7 @@ context "when declaration strategy is unknown" do let(:declaration_strategy) { :bananas } - it "should raise error" do + it "raises error" do expect { subject }.to raise_error(/Unknown declaration strategy '#{declaration_strategy}' received.'/) end end diff --git a/spec/helpers/ui_spec.rb b/spec/helpers/ui_spec.rb index 8f7c471..bd4299b 100644 --- a/spec/helpers/ui_spec.rb +++ b/spec/helpers/ui_spec.rb @@ -6,44 +6,44 @@ let(:logger) { Logger.new($stdout) } describe ".crash" do - it "should raise and print red message" do + it "raises and print red message" do expect(message).to receive(:red) - expect(UI).to receive(:logger).and_return(logger) + expect(described_class).to receive(:logger).and_return(logger) expect(logger).to receive(:fatal) - expect { UI.crash(message) }.to raise_error(message) + expect { described_class.crash(message) }.to raise_error(message) end end describe ".debug" do - it "should print cyan message" do + it "prints cyan message" do expect(message).to receive(:cyan) - expect(UI).to receive(:logger).and_return(logger) + expect(described_class).to receive(:logger).and_return(logger) expect(logger).to receive(:debug) - UI.debug(message) + described_class.debug(message) end end describe ".success" do - it "should print green message" do + it "prints green message" do expect(message).to receive(:green) - expect(UI).to receive(:logger).and_return(logger) + expect(described_class).to receive(:logger).and_return(logger) expect(logger).to receive(:info) - UI.success(message) + described_class.success(message) end end describe ".warn" do - it "should print yellow message" do + it "prints yellow message" do expect(message).to receive(:yellow) - expect(UI).to receive(:logger).and_return(logger) + expect(described_class).to receive(:logger).and_return(logger) expect(logger).to receive(:warn) - UI.warn(message) + described_class.warn(message) end end describe "any action" do - it "should instantiate logger" do - UI.success("Test ran successfully (hopefully)") + it "instantiates logger" do + expect { described_class.success("Test ran successfully (hopefully)") }.not_to raise_error end end end diff --git a/spec/models/arguments_spec.rb b/spec/models/arguments_spec.rb index 22a81d3..7b55911 100644 --- a/spec/models/arguments_spec.rb +++ b/spec/models/arguments_spec.rb @@ -3,21 +3,23 @@ require "arkana/models/arguments" RSpec.describe Arguments do + subject { described_class.new } + before { ARGV.replace([]) } - subject { Arguments.new } describe "#config_filepath" do context "when the option is ommitted in ARGV" do - it "should default to the default value" do + it "defaults to the default value" do expect(subject.config_filepath).to eq ".arkana.yml" end end context "when the option is passed in ARGV" do let(:expected_path) { "rspec/file/path" } + before { ARGV.replace(["--config-filepath", expected_path]) } - it "should return the argument passed" do + it "returns the argument passed" do expect(subject.config_filepath).to eq expected_path end end @@ -26,14 +28,14 @@ describe "#dotenv_filepath" do context "when the option is ommitted in ARGV" do describe "when .env file exists" do - it "should default to the default value" do + it "defaults to the default value" do expect(File).to receive(:exist?).with(".env").and_return(true) expect(subject.dotenv_filepath).to eq ".env" end end describe "when .env file doesn't exist" do - it "should be nil" do + it "is nil" do expect(File).to receive(:exist?).with(".env").and_return(false) expect(subject.dotenv_filepath).to be_nil end @@ -42,9 +44,10 @@ context "when the option is passed in ARGV" do let(:expected_path) { "rspec/file/path" } + before { ARGV.replace(["--dotenv-filepath", expected_path]) } - it "should return the argument passed" do + it "returns the argument passed" do expect(subject.dotenv_filepath).to eq expected_path end end @@ -52,16 +55,17 @@ describe "#flavor" do context "when the option is ommitted in ARGV" do - it "should default to nil" do + it "defaults to nil" do expect(subject.flavor).to be_nil end end context "when the option is passed in ARGV" do let(:expected_flavor) { "some_flavor" } + before { ARGV.replace(["--flavor", expected_flavor]) } - it "should return the argument passed" do + it "returns the argument passed" do expect(subject.flavor).to eq expected_flavor end end diff --git a/spec/models/config_spec.rb b/spec/models/config_spec.rb index cba8531..67569bf 100644 --- a/spec/models/config_spec.rb +++ b/spec/models/config_spec.rb @@ -1,14 +1,15 @@ # frozen_string_literal: true RSpec.describe Config do + subject { described_class.new(YAML.load_file(yaml_file)) } + let(:yaml_file) { "spec/fixtures/arkana-fixture.yml" } - subject { Config.new(YAML.load_file(yaml_file)) } describe ".new" do context "when the yaml file doesn't specify elements" do - subject { Config.new({}) } + subject { described_class.new({}) } - it "should fallback each property to their respective default value" do + it "fallbacks each property to their respective default value" do expect(subject.environments).to be_empty expect(subject.environment_secrets).to be_empty expect(subject.global_secrets).to be_empty @@ -27,7 +28,7 @@ end context "when yaml configurations are provided" do - it "should correctly assign each key/value pair to their respective property" do + it "correctlies assign each key/value pair to their respective property" do expect(subject.environments).to eq %w[Debug Release DebugPlusMore ReleasePlusMore] expect(subject.environment_secrets).to eq %w[ServiceKey Server] expect(subject.global_secrets).to eq %w[Domain Global] @@ -48,51 +49,53 @@ describe `#environment_keys` do context "when there are no environments" do - let(:yaml_file) { "spec/fixtures/arkana-empty-environments-fixture.yml" } subject { super().environment_keys } - it { should be_empty } + let(:yaml_file) { "spec/fixtures/arkana-empty-environments-fixture.yml" } + + it { is_expected.to be_empty } end context "when there is one or more environments" do context "when there are no environment secrets" do - let(:yaml_file) { "spec/fixtures/arkana-empty-environment-secrets-fixture.yml" } subject { super().environment_keys } - it { should be_empty } + let(:yaml_file) { "spec/fixtures/arkana-empty-environment-secrets-fixture.yml" } + + it { is_expected.to be_empty } end context "when there is one or more environment secrets" do - it "should generate a new key for each environment + environment secret pair" do + it "generates a new key for each environment + environment secret pair" do expect(subject.environment_keys.count).to eq(4 * 2) # There are 4 environments and 2 environment secrets end - it "should have all keys with a prefix of the environment secret name" do - expect(subject.environment_keys.all? do |key| + it "has all keys with a prefix of the environment secret name" do + expect(subject.environment_keys).to be_all do |key| subject.environment_secrets.any? { |secret| key.start_with?(secret) } - end).to be_truthy + end end - it "should have all keys with a suffix of the capitalized environment name" do - expect(subject.environment_keys.all? do |key| + it "has all keys with a suffix of the capitalized environment name" do + expect(subject.environment_keys).to be_all do |key| subject.environments.any? { |env| key.end_with?(env) } - end).to be_truthy + end end end end end - describe :all_keys do - it "should not be empty" do - expect(subject.all_keys).to_not be_empty + describe `#all_keys` do + it "is not empty" do + expect(subject.all_keys).not_to be_empty end - it "should contain the contents of the global keys + environment keys" do + it "contains the contents of the global keys + environment keys" do expect(subject.all_keys).to eq(subject.global_secrets + subject.environment_keys) end describe "#count" do - it "should match the number of environments times the number of environment secrets, plus the number of global secrets" do + it "matches the number of environments times the number of environment secrets, plus the number of global secrets" do expect(subject.all_keys.count).to eq((subject.environments.count * subject.environment_secrets.count) + subject.global_secrets.count) end end diff --git a/spec/models/secret_spec.rb b/spec/models/secret_spec.rb index 2e79447..b463d61 100644 --- a/spec/models/secret_spec.rb +++ b/spec/models/secret_spec.rb @@ -1,15 +1,16 @@ # frozen_string_literal: true RSpec.describe Secret do + subject { described_class.new(key: key, protocol_key: protocol_key, encoded_value: encoded_value, type: type) } + let(:environment) { "TestEnv" } let(:key) { "#{protocol_key}#{environment}" } let(:protocol_key) { "LoremIpsum" } let(:encoded_value) { SecureRandom.base64(12) } let(:type) { :string } - subject { Secret.new(key: key, protocol_key: protocol_key, encoded_value: encoded_value, type: type) } describe ".new" do - it "should have all the properties properly assigned" do + it "has all the properties properly assigned" do expect(subject.key).to eq key expect(subject.protocol_key).to eq protocol_key expect(subject.encoded_value).to eq encoded_value @@ -23,13 +24,13 @@ context "when key is equal to protocol_key" do let(:key) { protocol_key } - it "should return :global" do + it "returns :global" do expect(subject).to eq :global end end context "when 'protocol_key' is a prefix of the 'key'" do - it "should return the remaining suffix (which is the environment)" do + it "returns the remaining suffix (which is the environment)" do expect(subject).to eq environment end end @@ -38,7 +39,7 @@ let(:key) { "bar#{environment}" } let(:protocol_key) { "foo" } - it "should raise" do + it "raises" do expect { subject }.to raise_error(/Precondition failure: the protocol_key '#{protocol_key}' is not the same as the key '#{key}' nor is its prefix. This state shouldn't be possible./) end end diff --git a/spec/models/template_arguments_spec.rb b/spec/models/template_arguments_spec.rb index dc71a83..e54916a 100644 --- a/spec/models/template_arguments_spec.rb +++ b/spec/models/template_arguments_spec.rb @@ -1,6 +1,15 @@ # frozen_string_literal: true RSpec.describe TemplateArguments do + subject do + described_class.new( + environment_secrets: environment_secrets, + global_secrets: global_secrets, + config: config, + salt: salt, + ) + end + let(:config) { Config.new(YAML.load_file("spec/fixtures/arkana-fixture.yml")) } let(:salt) { SaltGenerator.generate } let(:environment_secrets) do @@ -21,15 +30,6 @@ ) end - subject do - TemplateArguments.new( - environment_secrets: environment_secrets, - global_secrets: global_secrets, - config: config, - salt: salt, - ) - end - before do config.all_keys.each do |key| allow(ENV).to receive(:[]).with(key).and_return("value") @@ -37,7 +37,7 @@ end describe ".new" do - it "should have all the properties properly assigned" do + it "has all the properties properly assigned" do expect(subject.instance_variable_get(:@environments)).to eq config.environments expect(subject.instance_variable_get(:@salt)).to eq salt expect(subject.instance_variable_get(:@environment_secrets)).to eq environment_secrets @@ -51,23 +51,25 @@ end describe ".environment_protocol_secrets" do - let(:environment) { "Debug" } subject { super().environment_protocol_secrets(environment) } - it "should return only the secrets specific to the given environment" do + let(:environment) { "Debug" } + + it "returns only the secrets specific to the given environment" do expect(subject.count).to eq 2 expect(subject.map(&:key)).to eq ["ServiceKey#{environment}", "Server#{environment}"] end end describe ".generate_test_secret" do - let(:key) { "Lorem" } subject { super().generate_test_secret(key: key) } - it "should return a secret of type string" do + let(:key) { "Lorem" } + + it "returns a secret of type string" do expect(subject.key).to eq key expect(subject.protocol_key).to eq key - expect(subject.encoded_value).to_not eq key + expect(subject.encoded_value).not_to eq key expect(subject.type).to eq :string end end diff --git a/spec/models/type_spec.rb b/spec/models/type_spec.rb index 0b6a02c..e65fa73 100644 --- a/spec/models/type_spec.rb +++ b/spec/models/type_spec.rb @@ -3,25 +3,25 @@ RSpec.describe Type do describe ".new" do context "when passing a 'true' string" do - subject { Type.new(string_value: "true") } + subject { described_class.new(string_value: "true") } - it "should return :boolean" do + it "returns :boolean" do expect(subject).to eq :boolean end end context "when passing a 'false' string" do - subject { Type.new(string_value: "false") } + subject { described_class.new(string_value: "false") } - it "should return :boolean" do + it "returns :boolean" do expect(subject).to eq :boolean end end context "when passing anything that is not 'true' or 'false' string" do - subject { Type.new(string_value: "lorem ipsum") } + subject { described_class.new(string_value: "lorem ipsum") } - it "should return :string" do + it "returns :string" do expect(subject).to eq :string end end diff --git a/spec/salt_generator_spec.rb b/spec/salt_generator_spec.rb index 2b9983d..c50306f 100644 --- a/spec/salt_generator_spec.rb +++ b/spec/salt_generator_spec.rb @@ -2,14 +2,14 @@ RSpec.describe SaltGenerator do describe ".generate" do - subject { SaltGenerator.generate } + subject { described_class.generate } describe "#raw" do - it "should return an array of integers" do - expect(subject.raw).to all(be_kind_of(Integer)) + it "returns an array of integers" do + expect(subject.raw).to all(be_a(Integer)) end - it "should have #{SaltGenerator::SALT_LENGTH} elements" do + it "has #{SaltGenerator::SALT_LENGTH} elements" do expect(subject.raw.count).to eq SaltGenerator::SALT_LENGTH end end diff --git a/spec/swift_code_generator_spec.rb b/spec/swift_code_generator_spec.rb index 76ee88e..7846bc0 100644 --- a/spec/swift_code_generator_spec.rb +++ b/spec/swift_code_generator_spec.rb @@ -55,8 +55,8 @@ def path(arg1, arg2, arg3 = nil) Pathname.new(File.join(arg1and2, arg3)) if arg3 end - it "should generate all necessary directories and files" do - SwiftCodeGenerator.generate(template_arguments: template_arguments, config: config) + it "generates all necessary directories and files" do + described_class.generate(template_arguments: template_arguments, config: config) expect(Pathname.new(config.result_path)).to be_directory expect(path(swift_package_dir, "README.md")).to be_file expect(path(swift_package_dir, "Package.swift")).to be_file @@ -67,27 +67,27 @@ def path(arg1, arg2, arg3 = nil) end context "when 'config.package_manager'" do - context "is 'cocoapods'" do + context "when is 'cocoapods'" do before do allow(config).to receive(:package_manager).and_return("cocoapods") - SwiftCodeGenerator.generate(template_arguments: template_arguments, config: config) + described_class.generate(template_arguments: template_arguments, config: config) end - it "should generate podspec files" do + it "generates podspec files" do expect(path(swift_package_dir, "#{config.pod_name.capitalize_first_letter}.podspec")).to be_file expect(path(interface_swift_package_dir, "#{config.pod_name.capitalize_first_letter}Interfaces.podspec")).to be_file end end - context "is not 'cocoapods'" do + context "when is not 'cocoapods'" do before do allow(config).to receive(:package_manager).and_return("spm") - SwiftCodeGenerator.generate(template_arguments: template_arguments, config: config) + described_class.generate(template_arguments: template_arguments, config: config) end - it "should not generate podspec files" do - expect(path(swift_package_dir, "#{config.pod_name.capitalize_first_letter}.podspec")).to_not be_file - expect(path(interface_swift_package_dir, "#{config.pod_name.capitalize_first_letter}Interfaces.podspec")).to_not be_file + it "does not generate podspec files" do + expect(path(swift_package_dir, "#{config.pod_name.capitalize_first_letter}.podspec")).not_to be_file + expect(path(interface_swift_package_dir, "#{config.pod_name.capitalize_first_letter}Interfaces.podspec")).not_to be_file end end end @@ -95,14 +95,14 @@ def path(arg1, arg2, arg3 = nil) context "when 'config.should_generate_unit_tests' is true" do before do allow(config).to receive(:should_generate_unit_tests).and_return(true) - SwiftCodeGenerator.generate(template_arguments: template_arguments, config: config) + described_class.generate(template_arguments: template_arguments, config: config) end - it "should generate test folder and files" do + it "generates test folder and files" do expect(path(swift_package_dir, "Tests", "#{config.import_name}Tests.swift")).to be_file end - it "should contain '.testTarget(' in Package.swift" do + it "contains '.testTarget(' in Package.swift" do expect(File.read(path(swift_package_dir, "Package.swift"))).to match(/\.testTarget\(/) end end @@ -110,16 +110,16 @@ def path(arg1, arg2, arg3 = nil) context "when 'config.should_generate_unit_tests' is false" do before do allow(config).to receive(:should_generate_unit_tests).and_return(false) - SwiftCodeGenerator.generate(template_arguments: template_arguments, config: config) + described_class.generate(template_arguments: template_arguments, config: config) end - it "should not generate test folder or files" do - expect(path(swift_package_dir, "Tests", "#{config.import_name}Tests.swift")).to_not be_file - expect(path(swift_package_dir, "Tests")).to_not be_directory + it "does not generate test folder or files" do + expect(path(swift_package_dir, "Tests", "#{config.import_name}Tests.swift")).not_to be_file + expect(path(swift_package_dir, "Tests")).not_to be_directory end - it "should not contain '.testTarget(' in Package.swift" do - expect(File.read(path(swift_package_dir, "Package.swift"))).to_not match(/\.testTarget\(/) + it "does not contain '.testTarget(' in Package.swift" do + expect(File.read(path(swift_package_dir, "Package.swift"))).not_to match(/\.testTarget\(/) end end end diff --git a/spec/version_spec.rb b/spec/version_spec.rb deleted file mode 100644 index c573918..0000000 --- a/spec/version_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe Arkana do - it "has a version number" do - expect(Arkana::VERSION).not_to be nil - end -end