require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") require 'statemachine/generate/java/java_statemachine' describe Statemachine::Statemachine, "(Java)" do before(:each) do remove_test_dir("java") @output = test_dir("java") @sm = Statemachine.build {} end def generate_turnstile_sm @sm = Statemachine.build do trans :locked, :coin, :unlocked, :unlock trans :unlocked, :pass, :locked, :lock trans :locked, :pass, :locked, :alarm trans :unlocked, :coin, :locked, :thanks end @sm.to_java(:output => @output, :name => "JavaTurnstile", :package => "test.turnstile") end def empty_sm_lines @sm.to_java(:name => "JavaTest", :output => @output, :package => "test.blank") filename = File.join(@output, "test", "blank", "JavaTest.java") File.should exist( filename) lines = IO.read(filename).split("\n") return lines end def sm_lines generate_turnstile_sm filename = File.join(@output, "test", "turnstile", "JavaTurnstile.java") File.should exist( filename) return IO.read(filename).split("\n") end def context_lines generate_turnstile_sm filename = File.join(@output, "test", "turnstile", "JavaTurnstileContext.java") File.should exist( filename) return IO.read(filename).split("\n") end def find_lines_after(lines, goose) while !lines.empty? return lines if lines.shift.strip == goose end raise "Can't find desired line: #{goose}" end it "should error if no output dir is specified" do lambda { @sm.to_java }.should raise_error("Please specify an output directory. (:output => 'where/you/want/your/code')") end it "should error if output dir doesn't exist" do lambda { @sm.to_java(:output => "/blah") }.should raise_error("Output dir '/blah' doesn't exist.") end it "should error if no class name is specified" do lambda { @sm.to_java(:output => @output) }.should raise_error("Please specify a name for the statemachine. (:name => 'SomeName')") end it "should generate a class" do @sm.to_java(:name => "JavaTest", :output => @output) File.should exist(File.join(@output, "JavaTest.java")) end it "should generate a class in a package" do lines = empty_sm_lines lines.shift.should == "// This file was generated by the Ruby Statemachine Library (http://slagyr.github.com/statemachine)." lines.shift.include?("// Generated at ").should == true lines.shift.should == "package test.blank;" lines.shift.should == "" lines.shift.should == "public class JavaTest" lines.shift.should == "{" lines.last.should == "}" end it "should generate sm boilerplate code" do lines = empty_sm_lines lines = find_lines_after(lines, "// The following is boiler plate code standard to all statemachines") lines.shift.should == " private JavaTestContext context;" lines.shift.should == "" lines.shift.should == " public JavaTest(JavaTestContext context)" lines.shift.should == " {" lines.shift.should == " this.context = context;" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public JavaTestContext getContext()" lines.shift.should == " {" lines.shift.should == " return context;" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public State getState()" lines.shift.should == " {" lines.shift.should == " return state;" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void setState(State newState)" lines.shift.should == " {" lines.shift.should == " state = newState;" lines.shift.should == " }" end it "should generate the sm exception" do lines = empty_sm_lines lines = find_lines_after(lines, "// Standard exception class added to all statemachines.") lines.shift.should == " public static class StatemachineException extends RuntimeException" lines.shift.should == " {" lines.shift.should == " public StatemachineException(State state, String event)" lines.shift.should == " {" lines.shift.should == " super(\"Missing transition from the '\" + state.getClass().getName() + \"' state with the '\" + event + \"' event.\");" lines.shift.should == " }" lines.shift.should == " }" end it "should generate base state" do lines = empty_sm_lines lines = find_lines_after(lines, "// The base state") lines.shift.should == " public static abstract class State" lines.shift.should == " {" lines.shift.should == " protected JavaTest statemachine;" lines.shift.should == "" lines.shift.should == " public State(JavaTest statemachine)" lines.shift.should == " {" lines.shift.should == " this.statemachine = statemachine;" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " }" end it "should generate the context" do @sm.to_java(:name => "JavaTest", :output => @output, :package => "com.blah") filename = File.join(@output, "com", "blah", "JavaTestContext.java") File.should exist(filename) lines = IO.read(filename).split("\n") lines.shift.should == "// This file was generated by the Ruby Statemachine Library (http://slagyr.github.com/statemachine)." lines.shift.include?("// Generated at ").should == true lines.shift.should == "package com.blah;" lines.shift.should == "" lines.shift.should == "public interface JavaTestContext" lines.shift.should == "{" lines.shift.should == " // Actions" lines.shift.should == "}" lines.should be_empty end it "should generate the state instance variables" do lines = find_lines_after(sm_lines, "// State instances") lines.shift.should == " public final State LOCKED = new LockedState(this);" lines.shift.should == " public final State UNLOCKED = new UnlockedState(this);" lines.shift.should == " private State state = LOCKED;" end it "should generate all the sm event handlers" do lines = find_lines_after(sm_lines, "// Event delegation") lines.shift.should == " public void coin()" lines.shift.should == " {" lines.shift.should == " state.coin();" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void pass()" lines.shift.should == " {" lines.shift.should == " state.pass();" lines.shift.should == " }" lines.shift.should == "" end it "should generate all the default event handlers" do lines = find_lines_after(sm_lines, "// The base state") lines.shift.should == " public static abstract class State" lines.shift.should == " {" lines.shift.should == " protected JavaTurnstile statemachine;" lines.shift.should == "" lines.shift.should == " public State(JavaTurnstile statemachine)" lines.shift.should == " {" lines.shift.should == " this.statemachine = statemachine;" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void coin()" lines.shift.should == " {" lines.shift.should == " throw new StatemachineException(this, \"coin\");" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void pass()" lines.shift.should == " {" lines.shift.should == " throw new StatemachineException(this, \"pass\");" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " }" end it "should generate state classes" do lines = find_lines_after(sm_lines, "// State implementations") lines.shift.should == " public static class LockedState extends State" lines.shift.should == " {" lines.shift.should == " public LockedState(JavaTurnstile statemachine)" lines.shift.should == " {" lines.shift.should == " super(statemachine);" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void coin()" lines.shift.should == " {" lines.shift.should == " statemachine.getContext().unlock();" lines.shift.should == " statemachine.setState(statemachine.UNLOCKED);" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void pass()" lines.shift.should == " {" lines.shift.should == " statemachine.getContext().alarm();" lines.shift.should == " statemachine.setState(statemachine.LOCKED);" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public static class UnlockedState extends State" lines.shift.should == " {" lines.shift.should == " public UnlockedState(JavaTurnstile statemachine)" lines.shift.should == " {" lines.shift.should == " super(statemachine);" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void coin()" lines.shift.should == " {" lines.shift.should == " statemachine.getContext().thanks();" lines.shift.should == " statemachine.setState(statemachine.LOCKED);" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " public void pass()" lines.shift.should == " {" lines.shift.should == " statemachine.getContext().lock();" lines.shift.should == " statemachine.setState(statemachine.LOCKED);" lines.shift.should == " }" lines.shift.should == "" lines.shift.should == " }" lines.shift.should == "" end it "should generate all the context methods" do lines = find_lines_after(context_lines, "// Actions") lines.shift.should == " void alarm();" lines.shift.should == " void lock();" lines.shift.should == " void thanks();" lines.shift.should == " void unlock();" end end