Browse Source

CLDC-3945 Update validation generation (#3011)

* Allow passing a year to generating lettings validations docs task

* Allow passing a year to generating sales validations docs task

* Refactor

* Include missing validations

* Describe all soft validations

* Update model

* Refactor
pull/3043/head
kosiakkatrina 2 weeks ago committed by GitHub
parent
commit
f5973585ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 42
      app/services/documentation_generator.rb
  2. 61
      lib/tasks/generate_lettings_documentation.rake
  3. 63
      lib/tasks/generate_sales_documentation.rake
  4. 202
      spec/lib/tasks/generate_lettings_documentation_spec.rb
  5. 202
      spec/lib/tasks/generate_sales_documentation_spec.rb
  6. 28
      spec/services/documentation_generator_spec.rb

42
app/services/documentation_generator.rb

@ -8,10 +8,14 @@ class DocumentationGenerator
include Validations::LocalAuthorityValidations
include Validations::SoftValidations
include Validations::Sales::SoftValidations
def describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type)
form = FormHandler.instance.forms["current_#{log_type}"]
include Validations::SetupValidations
include Validations::HouseholdValidations
include Validations::PropertyValidations
include Validations::FinancialValidations
include Validations::TenancyValidations
include Validations::DateValidations
def describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type)
all_validation_methods.each do |meth|
if LogValidation.where(validation_name: meth.to_s, bulk_upload_specific: false, log_type:, collection_year: "#{form.start_date.year}/#{form.start_date.year + 1}").exists?
Rails.logger.info("Validation #{meth} already exists for #{form.start_date.year}")
@ -69,9 +73,9 @@ class DocumentationGenerator
end
end
def describe_soft_validations(client, all_validation_methods, all_helper_methods, log_type)
def describe_soft_validations(client, form, all_validation_methods, all_helper_methods, log_type)
validation_descriptions = {}
all_validation_methods[0..5].each do |meth|
all_validation_methods.each do |meth|
validation_source = method(meth).source
helper_methods_source = all_helper_methods.map { |helper_method|
if validation_source.include?(helper_method.to_s)
@ -87,10 +91,6 @@ class DocumentationGenerator
validation_descriptions[meth.to_s] = result
end
current_form = FormHandler.instance.forms["current_#{log_type}"]
previous_form = FormHandler.instance.forms["previous_#{log_type}"]
[current_form, previous_form].each do |form|
interruption_screen_pages = form.pages.select { |page| page.questions.first.type == "interruption_screen" }
interruption_screen_pages_grouped_by_question = interruption_screen_pages.group_by { |page| page.questions.first.id }
interruption_screen_pages_grouped_by_question.each do |_question_id, pages|
@ -99,6 +99,24 @@ class DocumentationGenerator
end
end
end
def validation_and_helper_methods(validation_classes)
all_validation_methods = validation_classes.map(&:instance_methods).flatten.select { |method| method.starts_with?("validate_") }.uniq
all_methods = validation_classes.map { |x| x.instance_methods + x.private_instance_methods }.flatten.uniq
all_helper_methods = all_methods - all_validation_methods
[all_validation_methods, all_helper_methods]
end
def get_soft_sales_methods
all_helper_methods = Validations::SoftValidations.private_instance_methods + Validations::Sales::SoftValidations.private_instance_methods
all_validation_methods = Validations::SoftValidations.instance_methods + Validations::Sales::SoftValidations.instance_methods
[all_helper_methods, all_validation_methods]
end
def get_soft_lettings_methods
all_helper_methods = Validations::SoftValidations.private_instance_methods
all_validation_methods = Validations::SoftValidations.instance_methods
[all_helper_methods, all_validation_methods]
end
private
@ -109,7 +127,7 @@ private
begin
client.chat(
parameters: {
model: "gpt-3.5-turbo",
model: "gpt-4o-mini",
messages: [
{
role: "system",
@ -201,7 +219,7 @@ private
def soft_validation_description(client, meth, validation_source, helper_methods_source)
client.chat(
parameters: {
model: "gpt-3.5-turbo",
model: "gpt-4o-mini",
messages: [
{
role: "system",

61
lib/tasks/generate_lettings_documentation.rake

@ -1,45 +1,53 @@
namespace :generate_lettings_documentation do
desc "Generate documentation for hard lettings validations"
task describe_lettings_validations: :environment do
task :describe_lettings_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_lettings_documentation:describe_lettings_validations['year']" if form_year.blank?
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "lettings")]
raise "No form found for given year" if form.blank?
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
include Validations::SetupValidations
include Validations::HouseholdValidations
include Validations::PropertyValidations
include Validations::FinancialValidations
include Validations::TenancyValidations
include Validations::DateValidations
include Validations::LocalAuthorityValidations
all_validation_methods = public_methods.select { |method| method.starts_with?("validate_") }
all_methods = [Validations::SetupValidations,
documentation_generator = DocumentationGenerator.new
validation_classes = [Validations::SetupValidations,
Validations::HouseholdValidations,
Validations::PropertyValidations,
Validations::FinancialValidations,
Validations::TenancyValidations,
Validations::DateValidations,
Validations::LocalAuthorityValidations].map { |x| x.instance_methods + x.private_instance_methods }.flatten
all_helper_methods = all_methods - all_validation_methods
Validations::LocalAuthorityValidations]
all_validation_methods, all_helper_methods = documentation_generator.validation_and_helper_methods(validation_classes)
DocumentationGenerator.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, "lettings")
documentation_generator.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, "lettings")
end
desc "Generate documentation for soft lettings validations"
task describe_soft_lettings_validations: :environment do
include Validations::SoftValidations
task :describe_soft_lettings_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_lettings_documentation:describe_soft_lettings_validations['year']" if form_year.blank?
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "lettings")]
raise "No form found for given year" if form.blank?
all_helper_methods = Validations::SoftValidations.private_instance_methods
all_validation_methods = Validations::SoftValidations.instance_methods
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
documentation_generator = DocumentationGenerator.new
all_helper_methods, all_validation_methods = documentation_generator.get_soft_lettings_methods
DocumentationGenerator.new.describe_soft_validations(client, all_validation_methods, all_helper_methods, "lettings")
documentation_generator.describe_soft_validations(client, form, all_validation_methods, all_helper_methods, "lettings")
end
desc "Generate documentation for hard bu lettings validations"
task describe_bu_lettings_validations: :environment do
task :describe_bu_lettings_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_lettings_documentation:describe_bu_lettings_validations['year']" if form_year.blank?
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "lettings")]
raise "No form found for given year" if form.blank?
row_parser_class = "BulkUpload::Lettings::Year#{form_year}::RowParser".constantize
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
[[FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(2023, "lettings")], BulkUpload::Lettings::Year2023::RowParser],
[FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(2024, "lettings")], BulkUpload::Lettings::Year2024::RowParser]].each do |form, row_parser_class|
all_validation_methods = row_parser_class.private_instance_methods.select { |method| method.starts_with?("validate_") }
all_helper_methods = row_parser_class.private_instance_methods(false) + row_parser_class.instance_methods(false) - all_validation_methods
@ -47,11 +55,14 @@ namespace :generate_lettings_documentation do
field_mapping_for_errors = row_parser_class.new.send("field_mapping_for_errors")
DocumentationGenerator.new.describe_bu_validations(client, form, row_parser_class, all_validation_methods, all_helper_methods, field_mapping_for_errors, "lettings")
end
end
desc "Generate documentation for lettings numeric validations"
task add_numeric_lettings_validations: :environment do
form = FormHandler.instance.forms["current_lettings"]
task :add_numeric_lettings_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_lettings_documentation:add_numeric_lettings_validations['year']" if form_year.blank?
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "lettings")]
raise "No form found for given year" if form.blank?
form.numeric_questions.each do |question|
next unless question.min || question.max

63
lib/tasks/generate_sales_documentation.rake

@ -1,56 +1,65 @@
namespace :generate_sales_documentation do
desc "Generate documentation for hard sales validations"
task describe_sales_validations: :environment do
task :describe_sales_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_sales_documentation:describe_sales_validations['year']" if form_year.blank?
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "sales")]
raise "No form found for given year" if form.blank?
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
include Validations::Sales::SetupValidations
include Validations::Sales::HouseholdValidations
include Validations::Sales::PropertyValidations
include Validations::Sales::FinancialValidations
include Validations::Sales::SaleInformationValidations
include Validations::SharedValidations
include Validations::LocalAuthorityValidations
all_validation_methods = public_methods.select { |method| method.starts_with?("validate_") }
all_methods = [Validations::Sales::SetupValidations,
documentation_generator = DocumentationGenerator.new
validation_classes = [Validations::Sales::SetupValidations,
Validations::Sales::HouseholdValidations,
Validations::Sales::PropertyValidations,
Validations::Sales::FinancialValidations,
Validations::Sales::SaleInformationValidations,
Validations::SharedValidations,
Validations::LocalAuthorityValidations].map { |x| x.instance_methods + x.private_instance_methods }.flatten
all_helper_methods = all_methods - all_validation_methods
DocumentationGenerator.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, "sales")
Validations::LocalAuthorityValidations]
all_validation_methods, all_helper_methods = documentation_generator.validation_and_helper_methods(validation_classes)
documentation_generator.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, "sales")
end
desc "Generate documentation for soft sales validations"
task describe_soft_sales_validations: :environment do
include Validations::SoftValidations
include Validations::Sales::SoftValidations
task :describe_soft_sales_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_sales_documentation:describe_soft_sales_validations['year']" if form_year.blank?
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "sales")]
raise "No form found for given year" if form.blank?
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
all_helper_methods = Validations::SoftValidations.private_instance_methods + Validations::Sales::SoftValidations.private_instance_methods
all_validation_methods = Validations::SoftValidations.instance_methods + Validations::Sales::SoftValidations.instance_methods
documentation_generator = DocumentationGenerator.new
all_helper_methods, all_validation_methods = documentation_generator.get_soft_sales_methods
DocumentationGenerator.new.describe_soft_validations(client, all_validation_methods, all_helper_methods, "sales")
documentation_generator.describe_soft_validations(client, form, all_validation_methods, all_helper_methods, "sales")
end
desc "Generate documentation for hard bu sales validations"
task describe_bu_sales_validations: :environment do
task :describe_bu_sales_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_sales_documentation:describe_bu_sales_validations['year']" if form_year.blank?
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "sales")]
raise "No form found for given year" if form.blank?
row_parser_class = "BulkUpload::Sales::Year#{form_year}::RowParser".constantize
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
[[FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(2023, "sales")], BulkUpload::Sales::Year2023::RowParser],
[FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(2024, "sales")], BulkUpload::Sales::Year2024::RowParser]].each do |form, row_parser_class|
all_validation_methods = row_parser_class.private_instance_methods.select { |method| method.starts_with?("validate_") }
all_helper_methods = row_parser_class.private_instance_methods(false) + row_parser_class.instance_methods(false) - all_validation_methods
field_mapping_for_errors = row_parser_class.new.send("field_mapping_for_errors")
DocumentationGenerator.new.describe_bu_validations(client, form, row_parser_class, all_validation_methods, all_helper_methods, field_mapping_for_errors, "sales")
end
end
desc "Generate documentation for sales numeric validations"
task add_numeric_sales_validations: :environment do
form = FormHandler.instance.forms["current_sales"]
task :add_numeric_sales_validations, %i[year] => :environment do |_task, args|
form_year = args[:year]&.to_i
raise "Usage: rake generate_sales_documentation:add_numeric_sales_validations['year']" if form_year.blank?
form = FormHandler.instance.forms[FormHandler.instance.form_name_from_start_year(form_year, "sales")]
raise "No form found for given year" if form.blank?
form.numeric_questions.each do |question|
next unless question.min || question.max

202
spec/lib/tasks/generate_lettings_documentation_spec.rb

@ -6,14 +6,24 @@ RSpec.describe "generate_lettings_documentation" do
subject(:task) { Rake::Task["generate_lettings_documentation:add_numeric_lettings_validations"] }
before do
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_lettings" => FormHandler.instance.forms["current_lettings"], "previous_lettings" => "2023_form", "next_lettings" => "2025_form" })
Rake.application.rake_require("tasks/generate_lettings_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "when the rake task is run" do
it "creates new validation documentation records" do
expect { task.invoke }.to change(LogValidation, :count)
allow(FormHandler.instance.forms).to receive(:[]).with("current_lettings").and_return(FormHandler.instance.forms["current_lettings"])
expect { task.invoke(2024) }.to change(LogValidation, :count)
expect(LogValidation.where(validation_name: "minimum").count).to be_positive
expect(LogValidation.where(validation_name: "range").count).to be_positive
any_min_validation = LogValidation.where(validation_name: "minimum").first
@ -30,8 +40,194 @@ RSpec.describe "generate_lettings_documentation" do
end
it "skips if the validation already exists in the database" do
task.invoke
expect { task.invoke }.not_to change(LogValidation, :count)
task.invoke(2024)
expect { task.invoke(2024) }.not_to change(LogValidation, :count)
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_lettings_documentation:add_numeric_lettings_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end
end
describe ":describe_lettings_validations", type: :task do
subject(:task) { Rake::Task["generate_lettings_documentation:describe_lettings_validations"] }
let(:documentation_generator) { instance_double(DocumentationGenerator, describe_bu_validations: nil, validation_and_helper_methods: []) }
let(:client) { instance_double(OpenAI::Client) }
before do
allow(OpenAI::Client).to receive(:new).and_return(client)
allow(DocumentationGenerator).to receive(:new).and_return(documentation_generator)
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_lettings" => "2024_form", "previous_lettings" => "2023_form", "next_lettings" => "2025_form" })
Rake.application.rake_require("tasks/generate_lettings_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a year given" do
it "gets the correct form for next year" do
allow(FormHandler.instance.forms).to receive(:[]).with("next_lettings").and_return("2025_form")
expect(documentation_generator).to receive(:describe_hard_validations).with(client, "2025_form", anything, anything, "lettings")
task.invoke("2025")
end
it "gets the correct form for current year" do
allow(FormHandler.instance.forms).to receive(:[]).with("current_lettings").and_return("2024_form")
expect(documentation_generator).to receive(:describe_hard_validations).with(client, "2024_form", anything, anything, "lettings")
task.invoke("2024")
end
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_lettings_documentation:describe_lettings_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end
describe ":describe_bu_lettings_validations", type: :task do
subject(:task) { Rake::Task["generate_lettings_documentation:describe_bu_lettings_validations"] }
let(:documentation_generator) { instance_double(DocumentationGenerator, describe_bu_validations: nil) }
let(:client) { instance_double(OpenAI::Client) }
before do
allow(OpenAI::Client).to receive(:new).and_return(client)
allow(DocumentationGenerator).to receive(:new).and_return(documentation_generator)
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_lettings" => "2024_form", "previous_lettings" => "2023_form", "next_lettings" => "2025_form" })
Rake.application.rake_require("tasks/generate_lettings_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a year given" do
it "gets the correct form for next year" do
allow(FormHandler.instance.forms).to receive(:[]).with("next_lettings").and_return("2025_form")
expect(documentation_generator).to receive(:describe_bu_validations).with(client, "2025_form", anything, anything, anything, anything, "lettings")
task.invoke("2025")
end
it "gets the correct form for current year" do
allow(FormHandler.instance.forms).to receive(:[]).with("current_lettings").and_return("2024_form")
expect(documentation_generator).to receive(:describe_bu_validations).with(client, "2024_form", anything, anything, anything, anything, "lettings")
task.invoke("2024")
end
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_lettings_documentation:describe_bu_lettings_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end
describe ":describe_soft_lettings_validations", type: :task do
subject(:task) { Rake::Task["generate_lettings_documentation:describe_soft_lettings_validations"] }
let(:documentation_generator) { instance_double(DocumentationGenerator, describe_bu_validations: nil, get_soft_lettings_methods: []) }
let(:client) { instance_double(OpenAI::Client) }
before do
allow(OpenAI::Client).to receive(:new).and_return(client)
allow(DocumentationGenerator).to receive(:new).and_return(documentation_generator)
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_lettings" => "2024_form", "previous_lettings" => "2023_form", "next_lettings" => "2025_form" })
Rake.application.rake_require("tasks/generate_lettings_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a year given" do
it "gets the correct form for next year" do
allow(FormHandler.instance.forms).to receive(:[]).with("next_lettings").and_return("2025_form")
expect(documentation_generator).to receive(:describe_soft_validations).with(client, "2025_form", anything, anything, "lettings")
task.invoke("2025")
end
it "gets the correct form for current year" do
allow(FormHandler.instance.forms).to receive(:[]).with("current_lettings").and_return("2024_form")
expect(documentation_generator).to receive(:describe_soft_validations).with(client, "2024_form", anything, anything, "lettings")
task.invoke("2024")
end
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_lettings_documentation:describe_soft_lettings_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end

202
spec/lib/tasks/generate_sales_documentation_spec.rb

@ -6,14 +6,24 @@ RSpec.describe "generate_sales_documentation" do
subject(:task) { Rake::Task["generate_sales_documentation:add_numeric_sales_validations"] }
before do
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_sales" => FormHandler.instance.forms["current_sales"], "previous_sales" => "2023_form", "next_sales" => "2025_form" })
Rake.application.rake_require("tasks/generate_sales_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "when the rake task is run" do
it "creates new validation documentation records" do
expect { task.invoke }.to change(LogValidation, :count)
allow(FormHandler.instance.forms).to receive(:[]).with("current_sales").and_return(FormHandler.instance.forms["current_sales"])
expect { task.invoke(2024) }.to change(LogValidation, :count)
expect(LogValidation.where(validation_name: "minimum").count).to be_positive
expect(LogValidation.where(validation_name: "range").count).to be_positive
any_min_validation = LogValidation.where(validation_name: "minimum").first
@ -30,8 +40,194 @@ RSpec.describe "generate_sales_documentation" do
end
it "skips if the validation already exists in the database" do
task.invoke
expect { task.invoke }.not_to change(LogValidation, :count)
task.invoke(2024)
expect { task.invoke(2024) }.not_to change(LogValidation, :count)
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_sales_documentation:add_numeric_sales_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end
end
describe ":describe_sales_validations", type: :task do
subject(:task) { Rake::Task["generate_sales_documentation:describe_sales_validations"] }
let(:documentation_generator) { instance_double(DocumentationGenerator, describe_bu_validations: nil, validation_and_helper_methods: []) }
let(:client) { instance_double(OpenAI::Client) }
before do
allow(OpenAI::Client).to receive(:new).and_return(client)
allow(DocumentationGenerator).to receive(:new).and_return(documentation_generator)
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_sales" => "2024_form", "previous_sales" => "2023_form", "next_sales" => "2025_form" })
Rake.application.rake_require("tasks/generate_sales_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a year given" do
it "gets the correct form for next year" do
allow(FormHandler.instance.forms).to receive(:[]).with("next_sales").and_return("2025_form")
expect(documentation_generator).to receive(:describe_hard_validations).with(client, "2025_form", anything, anything, "sales")
task.invoke("2025")
end
it "gets the correct form for current year" do
allow(FormHandler.instance.forms).to receive(:[]).with("current_sales").and_return("2024_form")
expect(documentation_generator).to receive(:describe_hard_validations).with(client, "2024_form", anything, anything, "sales")
task.invoke("2024")
end
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_sales_documentation:describe_sales_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end
describe ":describe_bu_sales_validations", type: :task do
subject(:task) { Rake::Task["generate_sales_documentation:describe_bu_sales_validations"] }
let(:documentation_generator) { instance_double(DocumentationGenerator, describe_bu_validations: nil) }
let(:client) { instance_double(OpenAI::Client) }
before do
allow(OpenAI::Client).to receive(:new).and_return(client)
allow(DocumentationGenerator).to receive(:new).and_return(documentation_generator)
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_sales" => "2024_form", "previous_sales" => "2023_form", "next_sales" => "2025_form" })
Rake.application.rake_require("tasks/generate_sales_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a year given" do
it "gets the correct form for next year" do
allow(FormHandler.instance.forms).to receive(:[]).with("next_sales").and_return("2025_form")
expect(documentation_generator).to receive(:describe_bu_validations).with(client, "2025_form", anything, anything, anything, anything, "sales")
task.invoke("2025")
end
it "gets the correct form for current year" do
allow(FormHandler.instance.forms).to receive(:[]).with("current_sales").and_return("2024_form")
expect(documentation_generator).to receive(:describe_bu_validations).with(client, "2024_form", anything, anything, anything, anything, "sales")
task.invoke("2024")
end
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_sales_documentation:describe_bu_sales_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end
describe ":describe_soft_sales_validations", type: :task do
subject(:task) { Rake::Task["generate_sales_documentation:describe_soft_sales_validations"] }
let(:documentation_generator) { instance_double(DocumentationGenerator, describe_bu_validations: nil, get_soft_sales_methods: []) }
let(:client) { instance_double(OpenAI::Client) }
before do
allow(OpenAI::Client).to receive(:new).and_return(client)
allow(DocumentationGenerator).to receive(:new).and_return(documentation_generator)
Timecop.freeze(Time.zone.local(2025, 1, 1))
Singleton.__init__(FormHandler)
allow(FormHandler.instance).to receive(:forms).and_return({ "current_sales" => "2024_form", "previous_sales" => "2023_form", "next_sales" => "2025_form" })
Rake.application.rake_require("tasks/generate_sales_documentation")
Rake::Task.define_task(:environment)
task.reenable
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a year given" do
it "gets the correct form for next year" do
allow(FormHandler.instance.forms).to receive(:[]).with("next_sales").and_return("2025_form")
expect(documentation_generator).to receive(:describe_soft_validations).with(client, "2025_form", anything, anything, "sales")
task.invoke("2025")
end
it "gets the correct form for current year" do
allow(FormHandler.instance.forms).to receive(:[]).with("current_sales").and_return("2024_form")
expect(documentation_generator).to receive(:describe_soft_validations).with(client, "2024_form", anything, anything, "sales")
task.invoke("2024")
end
end
context "with no year given" do
it "raises an error" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake generate_sales_documentation:describe_soft_sales_validations['year']")
end
end
context "with an invalid year given" do
it "raises an error" do
expect { task.invoke("abc") }.to raise_error(RuntimeError, "No form found for given year")
end
end
context "with a year for non existing form" do
it "raises an error" do
expect { task.invoke("2022") }.to raise_error(RuntimeError, "No form found for given year")
end
end
end

28
spec/services/documentation_generator_spec.rb

@ -17,10 +17,11 @@ describe DocumentationGenerator do
describe ":describe_hard_validations" do
context "when the service is run with lettings type" do
let(:log_type) { "lettings" }
let(:form) { FormHandler.instance.forms["current_lettings"] }
it "creates new validation documentation records" do
expect(Rails.logger).to receive(:info).with(/described/).at_least(:once)
expect { described_class.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect { described_class.new.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect(LogValidation.where(validation_name: "validate_numeric_min_max").count).to eq(1)
any_validation = LogValidation.first
expect(any_validation.description).to eq("Validates the format.")
@ -37,12 +38,12 @@ describe DocumentationGenerator do
it "calls the client" do
expect(client).to receive(:chat)
described_class.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type)
described_class.new.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type)
end
it "skips if the validation already exists in the database" do
described_class.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type)
expect { described_class.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type) }.not_to change(LogValidation, :count)
described_class.new.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type)
expect { described_class.new.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type) }.not_to change(LogValidation, :count)
end
context "when the response is not a JSON" do
@ -51,7 +52,7 @@ describe DocumentationGenerator do
it "raises an error" do
expect(Rails.logger).to receive(:error).with(/Failed to save/).at_least(:once)
expect(Rails.logger).to receive(:error).with(/Error/).at_least(:once)
described_class.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type)
described_class.new.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type)
end
end
@ -61,17 +62,18 @@ describe DocumentationGenerator do
it "raises an error" do
expect(Rails.logger).to receive(:error).with(/Failed to save/).at_least(:once)
expect(Rails.logger).to receive(:error).with(/Error/).at_least(:once)
described_class.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type)
described_class.new.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type)
end
end
end
context "when the service is run with sales type" do
let(:log_type) { "sales" }
let(:form) { FormHandler.instance.forms["current_sales"] }
it "creates new validation documentation records" do
expect(Rails.logger).to receive(:info).with(/described/).at_least(:once)
expect { described_class.new.describe_hard_validations(client, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect { described_class.new.describe_hard_validations(client, form, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect(LogValidation.where(validation_name: "validate_numeric_min_max").count).to eq(1)
any_validation = LogValidation.first
expect(any_validation.description).to eq("Validates the format.")
@ -97,9 +99,10 @@ describe DocumentationGenerator do
context "when the service is run for lettings" do
let(:log_type) { "lettings" }
let(:form) { FormHandler.instance.forms["current_lettings"] }
it "creates new validation documentation records" do
expect { described_class.new.describe_soft_validations(client, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect { described_class.new.describe_soft_validations(client, form, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect(LogValidation.where(validation_name: "rent_soft_validation_triggered?").count).to be_positive
any_validation = LogValidation.first
expect(any_validation.description).to eq("Validates the format.")
@ -115,21 +118,22 @@ describe DocumentationGenerator do
it "calls the client" do
expect(client).to receive(:chat)
described_class.new.describe_soft_validations(client, all_validation_methods, all_helper_methods, log_type)
described_class.new.describe_soft_validations(client, form, all_validation_methods, all_helper_methods, log_type)
end
it "skips if the validation already exists in the database" do
described_class.new.describe_soft_validations(client, all_validation_methods, all_helper_methods, log_type)
expect { described_class.new.describe_soft_validations(client, all_validation_methods, all_helper_methods, log_type) }.not_to change(LogValidation, :count)
described_class.new.describe_soft_validations(client, form, all_validation_methods, all_helper_methods, log_type)
expect { described_class.new.describe_soft_validations(client, form, all_validation_methods, all_helper_methods, log_type) }.not_to change(LogValidation, :count)
end
end
context "when the service is run for sales" do
let(:log_type) { "sales" }
let(:form) { FormHandler.instance.forms["current_sales"] }
let(:all_validation_methods) { ["income2_outside_soft_range_for_ecstat?"] }
it "creates new validation documentation records" do
expect { described_class.new.describe_soft_validations(client, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect { described_class.new.describe_soft_validations(client, form, all_validation_methods, all_helper_methods, log_type) }.to change(LogValidation, :count)
expect(LogValidation.where(validation_name: "income2_outside_soft_range_for_ecstat?").count).to be_positive
any_validation = LogValidation.first
expect(any_validation.description).to eq("Validates the format.")

Loading…
Cancel
Save