diff --git a/lib/generator/case_values.rb b/lib/generator/case_values.rb new file mode 100644 index 0000000000..515d272b61 --- /dev/null +++ b/lib/generator/case_values.rb @@ -0,0 +1,25 @@ +module Generator + module CaseValues + class Extractor + def initialize(case_class:) + @case_class = case_class + end + + def cases(exercise_data) + extract_test_cases( + data: JSON.parse(exercise_data)['cases'] + ).map.with_index do |test, index| + @case_class.new(test.merge('index' => index)) + end + end + + private + + def extract_test_cases(data:) + data.flat_map do |entry| + entry.key?('cases') ? extract_test_cases(data: entry['cases']) : entry + end + end + end + end +end diff --git a/lib/generator/files/track_files.rb b/lib/generator/files/track_files.rb index d54430180c..9fe130368b 100644 --- a/lib/generator/files/track_files.rb +++ b/lib/generator/files/track_files.rb @@ -14,13 +14,18 @@ def filename(exercise_name) "#{exercise_name.tr('-', '_')}_cases" end - def proc_name(exercise_name) - filename(exercise_name).split('_').map(&:capitalize).join + def class_name(exercise_name) + filename(exercise_name)[0..-2].split('_').map(&:capitalize).join end def exercise_name(filename) %r{([^/]*)_cases\.rb$}.match(filename).captures[0].tr('_', '-') end + + def load_filename(track_path, exercise_name) + path = File.join(track_path, 'lib') + "%s/%s.rb" % [ path, filename(exercise_name) ] + end end module TrackFiles diff --git a/lib/generator/template_values.rb b/lib/generator/template_values.rb index a1aac124f5..a9a83851c9 100644 --- a/lib/generator/template_values.rb +++ b/lib/generator/template_values.rb @@ -16,23 +16,28 @@ def get_binding module TemplateValuesFactory def template_values - require cases_require_name - TemplateValues.new( abbreviated_commit_hash: canonical_data.abbreviated_commit_hash, version: version, - test_cases: test_cases_proc.call(canonical_data.to_s) + test_cases: extract ) end private - def cases_require_name - Files::GeneratorCases.filename(exercise_name) + def extract + load cases_load_name + extractor.cases(canonical_data.to_s) + end + + def extractor + CaseValues::Extractor.new( + case_class: Object.const_get(Files::GeneratorCases.class_name(exercise_name)) + ) end - def test_cases_proc - Object.const_get(Files::GeneratorCases.proc_name(exercise_name)) + def cases_load_name + Files::GeneratorCases.load_filename(paths.track, exercise_name) end end end diff --git a/test/fixtures/metadata/exercises/complex/canonical-data.json b/test/fixtures/metadata/exercises/complex/canonical-data.json new file mode 100644 index 0000000000..699953ed5a --- /dev/null +++ b/test/fixtures/metadata/exercises/complex/canonical-data.json @@ -0,0 +1,45 @@ +{ + "exercise": "beer-song", + "version": "1.0.0", + "cases": [ + { + "description": "verse", + "cases": [ + { + "description": "single verse", + "cases": [ + { + "description": "first generic verse", + "property": "verse", + "number": 99, + "expected": "99 bottles of beer on the wall, YAAAR" + }, + { + "description": "last generic verse", + "property": "verse", + "number": 3, + "expected": "3 bottles of beer on the wall, YAAAR" + } + ] + } + ] + }, + { + "description": "lyrics", + "cases": [ + { + "description": "multiple verses", + "cases": [ + { + "description": "first two verses", + "property": "verses", + "beginning": 99, + "end": 98, + "expected": "99 bottles of beer on the wall, YAR, PIRATES CAN'T COUNT" + } + ] + } + ] + } + ] +} diff --git a/test/fixtures/xruby/lib/beta_cases.rb b/test/fixtures/xruby/lib/beta_cases.rb index e69de29bb2..e442b4e531 100644 --- a/test/fixtures/xruby/lib/beta_cases.rb +++ b/test/fixtures/xruby/lib/beta_cases.rb @@ -0,0 +1,7 @@ +require 'exercise_cases' + +class BetaCase < ExerciseCase + def workload + assert_equal { "Beta.call('#{input}')" } + end +end diff --git a/test/generator/case_values_test.rb b/test/generator/case_values_test.rb new file mode 100644 index 0000000000..9fbcf7d0b2 --- /dev/null +++ b/test/generator/case_values_test.rb @@ -0,0 +1,30 @@ +require_relative '../test_helper' + +class ComplexCase < ExerciseCase + def workload + assert { Complex.foo(bar) } + end +end + +module Generator + module CaseValues + class ExtractorTest < Minitest::Test + def test_multi_level_auto_extraction + canonical_data = File.read('test/fixtures/metadata/exercises/complex/canonical-data.json') + cases = Extractor.new( + case_class: ComplexCase, + ).cases(canonical_data) + + expected = [ + ComplexCase.new(description: 'first generic verse', property: 'verse', number: 99, + expected: '99 bottles of beer on the wall, YAAAR', index: 0), + ComplexCase.new(description: 'last generic verse', property: 'verse', number: 3, + expected: '3 bottles of beer on the wall, YAAAR', index: 1), + ComplexCase.new(description: 'first two verses', property: 'verses', beginning: 99, end: 98, + expected: "99 bottles of beer on the wall, YAR, PIRATES CAN'T COUNT", index: 2) + ] + assert_equal expected, cases + end + end + end +end diff --git a/test/generator/files/track_files_test.rb b/test/generator/files/track_files_test.rb index 39311b765e..7ea9f9af30 100644 --- a/test/generator/files/track_files_test.rb +++ b/test/generator/files/track_files_test.rb @@ -25,9 +25,8 @@ def test_filename assert_equal 'two_parter_cases', GeneratorCases.filename(exercise_name) end - def test_proc_name - exercise_name = 'two-parter' - assert_equal 'TwoParterCases', GeneratorCases.proc_name(exercise_name) + def test_class_name + assert_equal 'TwoParterCase', GeneratorCases.class_name('two-parter') end end diff --git a/test/generator/template_values_test.rb b/test/generator/template_values_test.rb index 75abf8abf9..57a4e27afe 100644 --- a/test/generator/template_values_test.rb +++ b/test/generator/template_values_test.rb @@ -43,17 +43,58 @@ def canonical_data mock_canonical_data end + def paths + mock_paths = Minitest::Mock.new + mock_paths.expect :track, 'test/fixtures/xruby' + mock_paths + end + include TemplateValuesFactory end - def test_template_values - $LOAD_PATH.unshift 'test/fixtures/xruby/lib' + class ClassBasedTestTemplateValuesFactory + def exercise_name + 'beta' + end + + def version + 2 + end + + def canonical_data + mock_canonical_data = Minitest::Mock.new + mock_canonical_data.expect :abbreviated_commit_hash, nil + mock_canonical_data.expect :to_s, '{"cases":[]}' + mock_canonical_data + end + + def paths + mock_paths = Minitest::Mock.new + mock_paths.expect :track, 'test/fixtures/xruby' + mock_paths + end + + include TemplateValuesFactory + end + + def test_template_values_from_class + subject = ClassBasedTestTemplateValuesFactory.new + assert_instance_of TemplateValues, subject.template_values + end + + def test_template_values_loads_problem_case_classes subject = TestTemplateValuesFactory.new assert_instance_of TemplateValues, subject.template_values + assert Object.const_defined?(:AlphaCase) + assert Object.const_defined?(:AlphaCases) end def teardown - $LOAD_PATH.delete 'test/fixtures/xruby/lib' + [:AlphaCase, :AlphaCases].each do |classname| + if Object.const_defined?(classname) + Object.send(:remove_const, classname) + end + end end end end