Skip to content

Add triangle test generator #474

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 4 commits into from
Nov 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions exercises/triangle/.version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
37 changes: 15 additions & 22 deletions exercises/triangle/example.rb
Original file line number Diff line number Diff line change
@@ -1,44 +1,37 @@
class TriangleError < RuntimeError
module BookKeeping
VERSION = 1
end

class Triangle
attr_reader :a, :b, :c
def initialize(a, b, c)
@a = a
@b = b
@c = c
end
attr_reader :sides

def kind
fail TriangleError if illegal?
if equilateral?
:equilateral
elsif isosceles?
:isosceles
else
:scalene
def initialize(sides)
@sides = sides
if illegal?
@sides = []
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we no longer raising on an illegal triangle? I did not see a comment about this in the discussions here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The canonical data for the triangle problem was recently updated to test for properties instead of its type. Thoughts?


private

def sides
@sides ||= [a, b, c]
end

def equilateral?
sides.uniq.size == 1
end

def isosceles?
sides.uniq.size == 2
sides.uniq.size.between?(1, 2)
end

def scalene?
sides.uniq.size == 3
end

private

def illegal?
impossible_length_side? || violates_inequality?
end

def violates_inequality?
a, b, c = sides
a + b <= c || a + c <= b || b + c <= a
end

Expand Down
20 changes: 20 additions & 0 deletions exercises/triangle/example.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env ruby
gem 'minitest', '>= 5.0.0'
require 'minitest/autorun'
require_relative 'triangle'

# Test data version:
# <%= sha1 %>
class TriangleTest < Minitest::Test<% test_cases.each do |test_case| %>
def <%= test_case.test_name %>
<%= test_case.skipped %>
<%= test_case.workload %>
end
<% end %>
<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %>
def test_bookkeeping
skip
assert_equal <%= version.next %>, BookKeeping::VERSION
end
end

120 changes: 80 additions & 40 deletions exercises/triangle/triangle_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,91 +3,131 @@
require 'minitest/autorun'
require_relative 'triangle'

# Test data version:
# b806246
class TriangleTest < Minitest::Test
def test_equilateral_triangles_have_equal_sides
assert_equal :equilateral, Triangle.new(2, 2, 2).kind
def test_triangle_is_equilateral_if_all_sides_are_equal
# skip
triangle = Triangle.new([2, 2, 2])
assert triangle.equilateral?, "Expected 'true', triangle is equilateral."
end

def test_larger_equilateral_triangles_also_have_equal_sides
def test_triangle_is_not_equilateral_if_any_side_is_unequal
skip
assert_equal :equilateral, Triangle.new(10, 10, 10).kind
triangle = Triangle.new([2, 3, 2])
refute triangle.equilateral?, "Expected 'false', triangle is not equilateral."
end

def test_isosceles_triangles_have_last_two_sides_equal
def test_triangle_is_not_equilateral_if_no_sides_are_equal
skip
assert_equal :isosceles, Triangle.new(3, 4, 4).kind
triangle = Triangle.new([5, 4, 6])
refute triangle.equilateral?, "Expected 'false', triangle is not equilateral."
end

def test_isosceles_triangles_have_first_and_last_sides_equal
def test_all_zero_sides_are_illegal_so_the_triangle_is_not_equilateral
skip
assert_equal :isosceles, Triangle.new(4, 3, 4).kind
triangle = Triangle.new([0, 0, 0])
refute triangle.equilateral?, "Expected 'false', triangle is not equilateral."
end

def test_isosceles_triangles_have_two_first_sides_equal
def test_equilateral_triangle_sides_may_be_floats
skip
assert_equal :isosceles, Triangle.new(4, 4, 3).kind
triangle = Triangle.new([0.5, 0.5, 0.5])
assert triangle.equilateral?, "Expected 'true', triangle is equilateral."
end

def test_isosceles_triangles_have_in_fact_exactly_two_sides_equal
def test_triangle_is_isosceles_if_last_two_sides_are_equal
skip
assert_equal :isosceles, Triangle.new(10, 10, 2).kind
triangle = Triangle.new([3, 4, 4])
assert triangle.isosceles?, "Expected 'true', triangle is isosceles."
end

def test_isosceles_triangles_have_unequal_side_larger_than_equal_sides
def test_triangle_is_isosceles_if_first_two_sides_are_equal
skip
assert_equal :isosceles, Triangle.new(4, 7, 4).kind
triangle = Triangle.new([4, 4, 3])
assert triangle.isosceles?, "Expected 'true', triangle is isosceles."
end

def test_scalene_triangles_have_no_equal_sides
def test_triangle_is_isosceles_if_first_and_last_sides_are_equal
skip
assert_equal :scalene, Triangle.new(3, 4, 5).kind
triangle = Triangle.new([4, 3, 4])
assert triangle.isosceles?, "Expected 'true', triangle is isosceles."
end

def test_2a_equals_b_plus_c_looks_like_equilateral_but_is_not
def test_equilateral_triangles_are_also_isosceles
skip
assert_equal :scalene, Triangle.new(5, 4, 6).kind
triangle = Triangle.new([4, 4, 4])
assert triangle.isosceles?, "Expected 'true', triangle is isosceles."
end

def test_scalene_triangles_have_no_equal_sides_at_a_larger_scale_too
def test_triangle_is_not_isosceles_if_no_sides_are_equal
skip
assert_equal :scalene, Triangle.new(10, 11, 12).kind
triangle = Triangle.new([2, 3, 4])
refute triangle.isosceles?, "Expected 'false', triangle is not isosceles."
end

def test_scalene_triangles_have_no_equal_sides_in_descending_order_either
def test_sides_that_violate_triangle_inequality_are_not_isosceles_even_if_two_are_equal
skip
assert_equal :scalene, Triangle.new(5, 4, 2).kind
triangle = Triangle.new([1, 1, 3])
refute triangle.isosceles?, "Expected 'false', triangle is not isosceles."
end

def test_very_small_triangles_are_legal
def test_isosceles_triangle_sides_may_be_floats
skip
assert_equal :scalene, Triangle.new(0.4, 0.6, 0.3).kind
triangle = Triangle.new([0.5, 0.4, 0.5])
assert triangle.isosceles?, "Expected 'true', triangle is isosceles."
end

def test_triangles_with_no_size_are_illegal
def test_triangle_is_scalene_if_no_sides_are_equal
skip
assert_raises(TriangleError) do
Triangle.new(0, 0, 0).kind
end
triangle = Triangle.new([5, 4, 6])
assert triangle.scalene?, "Expected 'true', triangle is scalene."
end

def test_triangles_violating_triangle_inequality_are_illegal
def test_triangle_is_not_scalene_if_all_sides_are_equal
skip
assert_raises(TriangleError) do
Triangle.new(1, 1, 3).kind
end
triangle = Triangle.new([4, 4, 4])
refute triangle.scalene?, "Expected 'false', triangle is not scalene."
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did the tests for illegal triangles go?


def test_triangles_violating_triangle_inequality_are_illegal_2
def test_triangle_is_not_scalene_if_two_sides_are_equal
skip
assert_raises(TriangleError) do
Triangle.new(7, 3, 2).kind
end
triangle = Triangle.new([4, 4, 3])
refute triangle.scalene?, "Expected 'false', triangle is not scalene."
end

def test_triangles_violating_triangle_inequality_are_illegal_3
def test_sides_that_violate_triangle_inequality_are_not_scalene_even_if_they_are_all_different
skip
assert_raises(TriangleError) do
Triangle.new(1, 3, 1).kind
end
triangle = Triangle.new([7, 3, 2])
refute triangle.scalene?, "Expected 'false', triangle is not scalene."
end

def test_scalene_triangle_sides_may_be_floats
skip
triangle = Triangle.new([0.5, 0.4, 0.6])
assert triangle.scalene?, "Expected 'true', triangle is scalene."
end

# Problems in exercism evolve over time, as we find better ways to ask
# questions.
# The version number refers to the version of the problem you solved,
# not your solution.
#
# Define a constant named VERSION inside of the top level BookKeeping
# module, which may be placed near the end of your file.
#
# In your file, it will look like this:
#
# module BookKeeping
# VERSION = 1 # Where the version number matches the one in the test.
# end
#
# If you are curious, read more about constants on RubyDoc:
# http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html

def test_bookkeeping
skip
assert_equal 1, BookKeeping::VERSION
end
end

51 changes: 51 additions & 0 deletions lib/triangle_cases.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
class TriangleCase < OpenStruct
def test_name
initial = description.downcase
replaced = initial.gsub(/(true|false)/, expected_type)
if initial.eql?(replaced) && !initial.include?(triangle)
replaced = triangle + ' triangle ' + initial
end
'test_%s' % replaced.tr_s(', -', '_')
end

def workload
[
"triangle = Triangle.new(#{sides})",
indent("#{assert_or_refute} triangle.#{triangle}?, #{failure_message}")
].join("\n")
end

def indent(line)
' ' * 4 + line
end

def assert_or_refute
expected ? 'assert' : 'refute'
end

def failure_message
%Q("Expected '#{expected}', #{expected_type}.")
end

def expected_type
"triangle is #{expected ? '' : 'not '}#{triangle}"
end

def skipped
index.zero? ? '# skip' : 'skip'
end
end

TriangleCases = proc do |data|
i = 0
cases = []
data = JSON.parse(data).select { |key, value| key.to_s.match(/[^#]+/) }
data.keys.each do |triangle|
data[triangle]['cases'].each do |row|
row = row.merge(row.merge('index' => i, 'triangle' => triangle))
cases << TriangleCase.new(row)
i += 1
end
end
cases
end