Skip to content

Commit

Permalink
Test that we can load and run various file formats. Test code cleanup. (
Browse files Browse the repository at this point in the history
  • Loading branch information
noahgibbs authored Dec 16, 2023
1 parent 0aa0190 commit e150e71
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 27 deletions.
2 changes: 2 additions & 0 deletions lacci/lib/shoes/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ class SingletonError < Shoes::Error; end
class MultipleShoesSpecRunsError < Shoes::Error; end

class UnsupportedFeature < Shoes::Error; end

class BadFilenameError < Shoes::Error; end
end
19 changes: 19 additions & 0 deletions lib/scarpe/cats_cradle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ def event_init
end
end

def fiber_start
@manager_fiber.resume
end

def event_promise(event)
@event_promises[event] ||= ::Scarpe::Promise.new
end
Expand All @@ -109,13 +113,28 @@ def on_event(event, &block)
@waiting_fibers << { promise: event_promise(event), fiber: f }
end

def active_fiber(&block)
f = Fiber.new do
CCInstance.instance.instance_eval(&block)
end
p = ::Scarpe::Promise.new
p.fulfilled!
@waiting_fibers << { promise: p, fiber: f }
end

def wait(promise)
raise(Scarpe::InvalidPromiseError, "Must supply a promise to wait!") unless promise.is_a?(::Scarpe::Promise)

# Wait until this promise is complete before running again
@manager_fiber.transfer(promise)
end

def yield
p = ::Scarpe::Promise.new
p.fulfilled!
@manager_fiber.transfer(p)
end

# This returns a promise, which can be waited on using wait()
def fully_updated
@wrangler.promise_dom_fully_updated
Expand Down
29 changes: 2 additions & 27 deletions lib/scarpe/shoes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,13 @@ def self.run_shoes_spec_test_code(code, class_name: nil, test_name: nil)
class_name ||= ENV["SHOES_MINITEST_CLASS_NAME"] || "TestShoesSpecCode"
test_name ||= ENV["SHOES_MINITEST_METHOD_NAME"] || "test_shoes_spec"

require_relative "cats_cradle"

# We want Minitest assertions available in the test code.
# But this will normally run in a subprocess. So we need
# to run Minitest tests and then export the results.

# We create a test object based on CatsCradle, which will
# run the test as straight-line code, wait for appropriate
# events and generally make things well-behaved. But the
# test DSL isn't CatsCradle. It's based on Minitest and
# ShoesSpecTest (see below).
#
# Note that that means that using CatsCradle to "bounce"
# control back and forth for evented tricks isn't really
# an option. We may need to revisit all of this later...
test_obj = Object.new
class << test_obj
include Scarpe::CatsCradle
end
Scarpe::ShoesSpecTest.test_obj = test_obj
test_obj.instance_eval do
Scarpe::CCInstance.instance.instance_eval do
event_init

on_heartbeat do
on_event(:next_heartbeat) do
Minitest.run ARGV

shut_down_shoes_code
Scarpe::ShoesSpecTest.test_obj = nil
end
end

Expand All @@ -66,7 +45,6 @@ class << test_obj
end
end

# This is based on the CatsCradle proxies initially, but will diverge over time
class Scarpe::ShoesSpecProxy
attr_reader :obj
attr_reader :linkable_id
Expand Down Expand Up @@ -116,9 +94,6 @@ def respond_to_missing?(method_name, include_private = false)
class Scarpe::ShoesSpecTest < Minitest::Test
include Scarpe::Test::HTMLAssertions

class << self
attr_accessor :test_obj
end
Shoes::Drawable.drawable_classes.each do |drawable_class|
finder_name = drawable_class.dsl_name

Expand Down
161 changes: 161 additions & 0 deletions test/test_file_loader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# frozen_string_literal: true

require "test_helper"

class TestScarpeFileLoader < ShoesSpecLoggedTest
self.logger_dir = File.expand_path("#{__dir__}/../logger")

def file_load_test(app_code, test_code, extension)
test_method_name = self.name
test_class_name = self.class.name

sspec_file = File.expand_path(File.join __dir__, "sspec.json")
File.unlink(sspec_file) if File.exist?(sspec_file)

test_method_name = self.name
test_class_name = self.class.name

with_tempfiles([
[["scarpe_log_config", ".json"], JSON.dump(log_config_for_test)],
[["scarpe_app_#{test_method_name}", extension], app_code],
[["scarpe_test_#{test_method_name}", ".rb"], test_code || ""],
]) do |log_config, app_filename, test_filename|
if test_code
test_env = "SHOES_SPEC_TEST=\"#{test_filename}\""
else
test_env = ""
end

cmd = <<~TEST_CMD.gsub("\n", " ").gsub(/\s+/, " ")
SCARPE_DISPLAY_SERVICE=wv_local
SCARPE_HTML_RENDERER=calzini
SCARPE_LOG_CONFIG=\"#{log_config}\"
#{test_env}
SHOES_MINITEST_EXPORT_FILE=\"#{sspec_file}\"
SHOES_MINITEST_CLASS_NAME=\"#{test_class_name}\"
SHOES_MINITEST_METHOD_NAME=\"#{test_method_name}\"
LOCALAPPDATA=\"#{Dir.tmpdir}\"
ruby #{SCARPE_EXE} --debug --dev \"#{app_filename}\"
TEST_CMD

return system(cmd)
end
end

# Run a test with an app, adding Shoes-Spec code so it will exit immediately
def file_load_app_test(contents, extension, timeout: 10.0, exit_immediately: true)
test_code = <<~TEST_CODE
timeout #{timeout}
#{exit_immediately ? "exit_on_first_heartbeat" : ""}
TEST_CODE

file_load_test(contents, test_code, extension)
end

def file_load_spec_test(contents, extension)
file_load_test(contents, nil, extension)
end

def test_file_loader_simple_rb_file
with_tempfile("any_file_touch", "") do |tmp_location|
File.unlink(tmp_location) if File.exist?(tmp_location)

assert_equal true, file_load_app_test(<<~CODE, ".rb")
Shoes.app do
button "OK"
File.write(#{tmp_location.inspect}, "foo")
end
CODE

assert_equal "foo", File.read(tmp_location)
end
end

def test_file_loader_simple_rb_file_runs
with_tempfile("any_file_touch", "") do |tmp_location|
File.unlink(tmp_location) if File.exist?(tmp_location)

assert_equal true, file_load_app_test(<<~CODE, ".rb")
File.write(#{tmp_location.inspect}, "foo")
CODE

assert_equal "foo", File.read(tmp_location)
end
end

def test_file_loader_sspec_file_runs
with_tempfiles([["app_file_touch", ""], ["test_file_touch", ""]]) do |app_tmp_location, test_tmp_location|
File.unlink(app_tmp_location) if File.exist?(app_tmp_location)
File.unlink(test_tmp_location) if File.exist?(test_tmp_location)

assert_equal true, file_load_spec_test(<<~CODE, ".sspec")
---
----------- app code
Shoes.app do
button "OK"
File.write(#{app_tmp_location.inspect}, "foo")
end
----------- test code
assert_equal "OK", button().text
File.write(#{test_tmp_location.inspect}, "bar")
CODE

assert_equal "foo", File.read(app_tmp_location)
assert_equal "bar", File.read(test_tmp_location)
end
end

def test_file_loader_simple_app_with_shoes_spec_test_code_runs
with_tempfiles([
["app_file_touch", ""],
["test_file_touch", ""],
]) do |app_tmp_location, test_tmp_location|
test_code = <<~TEST_CODE
assert_equal "OK", button().text
File.write(#{test_tmp_location.inspect}, "quux")
TEST_CODE

with_tempfile("shoes_spec_code", test_code) do |sspec_location|

File.unlink(app_tmp_location) if File.exist?(app_tmp_location)
File.unlink(test_tmp_location) if File.exist?(test_tmp_location)

assert_equal true, file_load_test(<<~CODE, test_code, ".rb")
Shoes.app do
button "OK"
File.write(#{app_tmp_location.inspect}, "baz")
end
CODE

assert_equal "baz", File.read(app_tmp_location)
assert_equal "quux", File.read(test_tmp_location)
end
end
end

def test_file_loader_sspec_app_raise_fails
assert_equal false, file_load_spec_test(<<~CODE, ".sspec")
---
----------- app code
Shoes.app do
button "OK"
raise "ERROR!"
end
----------- test code
assert_equal "OK", button().text
CODE
end

def test_file_loader_sspec_test_raise_fails
assert_equal false, file_load_spec_test(<<~CODE, ".sspec")
---
----------- app code
Shoes.app do
button "OK"
raise "ERROR!"
end
----------- test code
assert_equal "OK", button().text
CODE
end
end

0 comments on commit e150e71

Please sign in to comment.