Skip to content

generators: Auto extract cases #568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Apr 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e30946e
add class_name to GeneratorCases
hilary Apr 23, 2017
77cac07
programmatically generate cases
hilary Apr 23, 2017
6134c48
extract CaseValues from TemplateValuesFactory
hilary Apr 24, 2017
982e9b3
separate logic for proc and auto extraction
hilary Apr 25, 2017
263e233
add #proc? to GeneratorCases
hilary Apr 25, 2017
068d1f5
fold Extract into TemplateValuesFactory
hilary Apr 25, 2017
75b81d7
Minor: Remove unnecessary whitespace changes.
Insti Apr 26, 2017
9f6a9e3
Remove redundant test.
Insti Apr 26, 2017
1700748
Inline the GammaCase rather than reading it from a file.
Insti Apr 26, 2017
33e0881
Move case values tests into a single file.
Insti Apr 26, 2017
f088d24
Remove redundant Mocks.
Insti Apr 26, 2017
001e608
Add test coverage for unimplmented extract method.
Insti Apr 26, 2017
012ce13
Eliminte LOAD_PATH modifications.
Insti Apr 26, 2017
9547152
Use fixture data we already have.
Insti Apr 26, 2017
d29bceb
Remove unnecessary inclusion of CaseValues
Insti Apr 26, 2017
8b2ae2a
Extract complex json to fixture file.
Insti Apr 26, 2017
8fb05bf
Remove unnecessary string conversions.
Insti Apr 26, 2017
45511ff
Explicitly load the ProblemCases file we need.
Insti Apr 26, 2017
0b47df3
remove proc support (not needed)
hilary Apr 26, 2017
d85ace4
Pass the data to be extracted to the extract method.
Insti Apr 26, 2017
4818a04
Pass the 'case_class'name in as an argument to Extractor
Insti Apr 26, 2017
bbde073
Don't use exercise_data in the initializer anymore.
Insti Apr 26, 2017
96dbd2b
exercise_name is not required by AutoExtractor anymore.
Insti Apr 26, 2017
42ff562
Rename 'extract' method to 'call'
Insti Apr 26, 2017
b52da2b
Merge pull request #4 from Insti/Refactor_Extractor
hilary Apr 26, 2017
557997c
rename Extractor#call to #cases
hilary Apr 26, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions lib/generator/case_values.rb
Original file line number Diff line number Diff line change
@@ -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
9 changes: 7 additions & 2 deletions lib/generator/files/track_files.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 12 additions & 7 deletions lib/generator/template_values.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
45 changes: 45 additions & 0 deletions test/fixtures/metadata/exercises/complex/canonical-data.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
]
}
]
}
7 changes: 7 additions & 0 deletions test/fixtures/xruby/lib/beta_cases.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'exercise_cases'

class BetaCase < ExerciseCase
def workload
assert_equal { "Beta.call('#{input}')" }
end
end
30 changes: 30 additions & 0 deletions test/generator/case_values_test.rb
Original file line number Diff line number Diff line change
@@ -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
5 changes: 2 additions & 3 deletions test/generator/files/track_files_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
47 changes: 44 additions & 3 deletions test/generator/template_values_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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