Publidata / opening_hours_converter

OpenStreetMap Opening Hours to Date & Date to Opening Hours
https://rubygems.org/gems/opening_hours_converter
GNU Affero General Public License v3.0
12 stars 3 forks source link

test generattion #22

Open Mziserman opened 5 years ago

Mziserman commented 5 years ago
time = ['2030 10:00-20:00',
  '10:00-20:00',
  '2030 week 1 10:00-20:00',
  '2030 week 1,3 10:00-20:00',
  '2030 week 1,3,10-30 10:00-20:00',
  '2030 week 1,3,10-30/2 10:00-20:00',
  '2030 week 1,3,10-30/2,50 10:00-20:00',
  'week 1 10:00-20:00',
  'week 1,3 10:00-20:00',
  'week 1,3,10-30 10:00-20:00',
  'week 1,3,10-30/2 10:00-20:00',
  'week 1,3,10-30/2,50 10:00-20:00',
  '2030 Jan 10:00-20:00',
  '2030 Jan 1-Jun 30 10:00-20:00',
  '2030 Jan-2050 Jun 10:00-20:00',
  '2030 Jan 10-2050 Jun 30 10:00-20:00',
  '2030-2050 10:00-20:00',
  'Jan 10:00-20:00',
  'Jan 1-Jun 30 10:00-20:00',
  'Jan 10-Jun 30 10:00-20:00']

offs = ['2030 off',
  'off',
  '2030 week 1 off',
  '2030 week 1,3 off',
  '2030 week 1,3,10-30 off',
  '2030 week 1,3,10-30/2 off',
  '2030 week 1,3,10-30/2,50 off',
  'week 1 off',
  'week 1,3 off',
  'week 1,3,10-30 off',
  'week 1,3,10-30/2 off',
  'week 1,3,10-30/2,50 off',
  '2030 Jan 1-31 off',
  '2030 Jan 1-Jun 30 off',
  '2030 Jan-2050 Jun off',
  '2030 Jan 10-2050 Jun 30 off',
  '2030-2050 off',
  'Jan 1-31 off',
  'Jan 1-Jun 30 off',
  'Jan 10-Jun 30 off']

ph_offs = ['2030 PH off',
  'PH off',
  '2030 week 1 PH off',
  '2030 week 1,3 PH off',
  '2030 week 1,3,10-30 PH off',
  '2030 week 1,3,10-30/2 PH off',
  '2030 week 1,3,10-30/2,50 PH off',
  'week 1 PH off',
  'week 1,3 PH off',
  'week 1,3,10-30 PH off',
  'week 1,3,10-30/2 PH off',
  'week 1,3,10-30/2,50 PH off',
  '2030 Jan 1-31 PH off',
  '2030 Jan 1-Jun 30 PH off',
  '2030 Jan 1-2050 Jun 30 PH off',
  '2030 Jan 10-2050 Jun 30 PH off',
  '2030-2050 PH off',
  'Jan 1-31 PH off',
  'Jan 1-Jun 30 PH off',
  'Jan 10-Jun 30 PH off']

multime = ['2030 10:00-20:00,21:00-23:00',
  '10:00-20:00,21:00-23:00',
  '2030 week 1 10:00-20:00,21:00-23:00',
  '2030 week 1,3 10:00-20:00,21:00-23:00',
  '2030 week 1,3,10-30 10:00-20:00,21:00-23:00',
  '2030 week 1,3,10-30/2 10:00-20:00,21:00-23:00',
  '2030 week 1,3,10-30/2,50 10:00-20:00,21:00-23:00',
  'week 1 10:00-20:00,21:00-23:00',
  'week 1,3 10:00-20:00,21:00-23:00',
  'week 1,3,10-30 10:00-20:00,21:00-23:00',
  'week 1,3,10-30/2 10:00-20:00,21:00-23:00',
  'week 1,3,10-30/2,50 10:00-20:00,21:00-23:00',
  '2030 Jan 10:00-20:00,21:00-23:00',
  '2030 Jan 1-Jun 30 10:00-20:00,21:00-23:00',
  '2030 Jan-2050 Jun 10:00-20:00,21:00-23:00',
  '2030 Jan 10-2050 Jun 30 10:00-20:00,21:00-23:00',
  '2030-2050 10:00-20:00,21:00-23:00',
  'Jan 10:00-20:00,21:00-23:00',
  'Jan 1-Jun 30 10:00-20:00,21:00-23:00',
  'Jan 10-Jun 30 10:00-20:00,21:00-23:00']

days = ['2030 Mo-Fr 10:00-20:00,21:00-23:00',
  'Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 week 1 Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 week 1,3 Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 week 1,3,10-30 Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 week 1,3,10-30/2 Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 week 1,3,10-30/2,50 Mo-Fr 10:00-20:00,21:00-23:00',
  'week 1 Mo-Fr 10:00-20:00,21:00-23:00',
  'week 1,3 Mo-Fr 10:00-20:00,21:00-23:00',
  'week 1,3,10-30 Mo-Fr 10:00-20:00,21:00-23:00',
  'week 1,3,10-30/2 Mo-Fr 10:00-20:00,21:00-23:00',
  'week 1,3,10-30/2,50 Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 Jan Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 Jan 1-Jun 30 Mo-Fr 10:00-20:00,21:00-23:00',
  '2030 Jan-2050 Jun Mo-Fr 10:00-20:00,21:00-23:00',
  '2030-2050 Mo-Fr 10:00-20:00,21:00-23:00',
  'Jan Mo-Fr 10:00-20:00,21:00-23:00',
  'Jan 1-Jun 30 Mo-Fr 10:00-20:00,21:00-23:00',
  'Jan 10-Jun 30 Mo-Fr 10:00-20:00,21:00-23:00']

combos = [time, offs, ph_offs, multime, days]
@products = []
combos.each_with_index do |ohs, index|
  combos.each_with_index do |combo, combo_index|
    next if index == combo_index

    @products += ohs.product(combo).map { |product| product.join('; ') }
  end
end
@products += time
@products += offs
@products += ph_offs
@products += multime
@products += days
passing = @products.select { |oh| @builder.build(@parser.parse(oh)) == oh }
not_passing = @products - passing

File.open('spec/automaticaly_generated_parser_passing_spec.rb', 'w') do |f|
  f.write("require 'opening_hours_converter'\n\nRSpec.describe OpeningHoursConverter::OpeningHoursParser, '#parse' do")
  f.write(passing.map do |oh|
    "  it \"#{oh}\" do\n    expect(OpeningHoursConverter::OpeningHoursBuilder.new.build(OpeningHoursConverter::OpeningHoursParser.new.parse('#{oh}'))).to eql('#{oh}')\n  end\n"
  end.join)
  f.write('end')
end
File.open('spec/automaticaly_generated_parser_not_passing_spec.rb', 'w') do |f|
  f.write("require 'opening_hours_converter'\n\nRSpec.describe OpeningHoursConverter::OpeningHoursParser, '#parse' do")
  f.write(not_passing.map do |oh|
    "  it \"#{oh}\" do\n    expect(OpeningHoursConverter::OpeningHoursBuilder.new.build(OpeningHoursConverter::OpeningHoursParser.new.parse('#{oh}'))).to eql('#{oh}')\n    # #{OpeningHoursConverter::OpeningHoursBuilder.new.build(OpeningHoursConverter::OpeningHoursParser.new.parse(oh))}\n  end\n"
  end.join)
  f.write('end')
end
Mziserman commented 5 years ago

génére 8000~ tests

Mziserman commented 5 years ago

comment faire mieux : liste de wide interval, liste d'intervals/state puis combo en gerant que si wide_interval.second.equal || contain wide_interval.first, alors overwrite

Mziserman commented 5 years ago

@products = []
wide_intervals = ['', '2030', '2030 week 1', '2030 week 1,3', '2030 week 1,3,10-30', '2030 week 1,3,10-30/2',
  '2030 week 1,3,10-30/2,50', 'week 1', 'week 1,3', 'week 1,3,10-30', 'week 1,3,10-30/2', 'week 1,3,10-30/2,50',
  '2030 Jan 01-31', '2030 Jan 01-2030 Jun 30', '2030 Jan 01-2050 Jun 30', '2030 Jan 10-2050 Jun 30', '2030-2050', 'Jan', 'Jan-Jun', 'Jan 10-Jun 30']
weekdays = ['', 'Mo', 'Mo,We-Fr,Su', 'Mo-We,Fr,Sa', 'PH', 'PH,Mo,We-Fr', 'Mo[1]', 'Su[-1]', 'We[2]']
weekdays = ['', 'Mo', 'Mo,We-Fr,Su', 'Mo-We,Fr,Sa', 'PH', 'PH,Mo,We-Fr']
hours_and_modifiers = ['10:00-20:00', 'off', '23:00-3:00', '9:00-12:30,14:00-18:30']
hours_and_modifiers = ['10:00-20:00', 'off', '09:00-12:30,14:00-18:30']
comments = ["", "\"commentaire\"", "\"commentaire avec des espaces\""]

possibilities = wide_intervals.product(weekdays, hours_and_modifiers, comments).map { |p| p.join(' ').gsub('  ', ' ').strip }

passing = possibilities.select { |oh| @builder.build(@parser.parse(oh)) == oh }
not_passing = possibilities - passing

File.open('spec/automaticaly_generated_no_combo_parser_passing_spec.rb', 'w') do |f|
  f.write("require 'opening_hours_converter'\n\nRSpec.describe OpeningHoursConverter::OpeningHoursParser, '#parse' do\n")
  f.write(passing.map do |oh|
    "  it '#{oh}' do\n    expect(OpeningHoursConverter::OpeningHoursBuilder.new.build(OpeningHoursConverter::OpeningHoursParser.new.parse('#{oh}'))).to eql('#{oh}')\n  end\n"
  end.join)
  f.write('end')
end
File.open('spec/automaticaly_generated_no_combo_parser_not_passing_spec.rb', 'w') do |f|
  f.write("require 'opening_hours_converter'\n\nRSpec.describe OpeningHoursConverter::OpeningHoursParser, '#parse' do\n")
  f.write(not_passing.map do |oh|
    "  it '#{oh}' do\n    expect(OpeningHoursConverter::OpeningHoursBuilder.new.build(OpeningHoursConverter::OpeningHoursParser.new.parse('#{oh}'))).to eql('#{oh}')\n    # #{OpeningHoursConverter::OpeningHoursBuilder.new.build(OpeningHoursConverter::OpeningHoursParser.new.parse(oh))}\n  end\n"
  end.join)
  f.write('end')
end
berkes commented 5 years ago

Would it not make more sense to have an "opening-hours-strings.txt" and fill that with edge-cases, and common cases, then have one test iterate over all the lines and check if we can parse it successfully?

Or is this code attempting something different?

Mziserman commented 5 years ago

The aim of this was to generate all the non edge case specs. For the edge case, I add them one by one in https://github.com/Publidata/opening_hours_converter/blob/master/spec/opening_hours_parser_spec.rb

It's not too readable and a txt file would make that better but I wonder if it wouldn't make it harder to determine what line broke if a test fail.

There is also the fact that if you build(parse(oh)) the resulting string can be modified while still being valid

For example

build(parse('Jan: 10:00-11:00')) => 'Jan 10:00-11:00' 

or

build(parse('Mo,Tu,We 10:00-11:00')) => 'Mo-We 10:00-11:00' 

In the generated exemples I avoided all the case where the output will be different.