Commits

Brett Giles committed cb738b2

Finalized FEST usage for cucumber

Additionally:
- upgraded monkeybars to remove "include_class" and use java_import
- tweaks to lqpl… to change how file chooser called
- ran flog on steps and support, all methods score < 15
- Added first Cucumber parameter transform :)

- Added monkey patches to JFileChooserFixture and File to improve readability of steps
- Added a fixture matcher for labels via patterns as a method
- added three new varieties of "sleep_until" to race_conditions module to improve step readability

Comments (0)

Files changed (20)

GUI/.rvmrc

-rvm --create use jruby@lqplfe

GUI/lib/java/monkeybars-1.1.1.jar

Binary file modified.

GUI/src/lqpl/lqpl_controller.rb

     file_exit_action_performed
     super
   end
-
+  
+  def my_frame
+    @__view.the_frame
+  end
+  
   def load(*args)
     cmp = CompilerServerConnection.get_instance
     cmp.connect
     qplfiles = FileNameExtensionFilter.new("LQPL source file", ["qpl"].to_java(:string))
     chooser.set_file_filter(qplfiles)
     chooser.set_current_directory(java.io.File.new(Dir.getwd))
-    rval = chooser.show_open_dialog(nil)
+    rval = chooser.show_open_dialog(self.my_frame)
     if rval == JFileChooser::APPROVE_OPTION
       fname = chooser.get_selected_file.get_absolute_path
       cmp = CompilerServerConnection.get_instance

GUI/src/lqpl/lqpl_view.rb

     @main_view_component.title = model.frame_title
   end
 
+  def the_frame
+    @main_view_component
+  end
 end
 
 case RbConfig::CONFIG["host_os"]
 when /darwin/i # OSX specific code
-  testing = java.lang.System.get_property("com.drogar.testing.jemmy")
+  testing = java.lang.System.get_property("com.drogar.testing.fest")
   if !testing or testing != "true"
     java.lang.System.set_property("apple.laf.useScreenMenuBar", "true")
   end

features/compile_an_lqpl_program.feature

   I want the program allow me to choose a "*.qpl" program and create a corresponding "*.qpo" file
   so I can start experimenting with LQPL
 
-	
   Scenario: I compile a simple qpl program
     Given I select "Compile" from the "File" menu
-    And I load "coin.qpl" from the directory "testdata/qplprograms"
-    Then "coin.qpo" should be created in "testdata/qplprograms" and be equal to "coin.reference.qpo"
+    And I load "coin.qpl" from the project directory "GUI/testdata/qplprograms"
+    Then "coin.qpo" should be created in the project directory "GUI/testdata/qplprograms" and be equal to "coin.reference.qpo"
     Then the messages field should contain:
       |partial|
       |Compile of coin.qpl was successful|
   
   Scenario: I try to compile a qpl program with syntax errors
     Given I select "Compile" from the "File" menu
-    And I load "invalidsyntax.qpl" from the directory "testdata/qplprograms"
+    And I load "invalidsyntax.qpl" from the project directory "GUI/testdata/qplprograms"
     Then the messages field should contain:
       |partial|
       |invalidsyntax.qpl was unsuccessful|
 
   Scenario: I try to compile a qpl program with syntax errors
     Given I select "Compile" from the "File" menu
-    And I load "invalidsemantics.qpl" from the directory "testdata/qplprograms"
+    And I load "invalidsemantics.qpl" from the project directory "GUI/testdata/qplprograms"
     Then the messages field should contain:
       |partial|
       |invalidsemantics.qpl was unsuccessful|
 
   Scenario: I compile a qpl program with warnings errors
     Given I select "Compile" from the "File" menu
-    And I load "invalidbalance.qpl" from the directory "testdata/qplprograms"
+    And I load "invalidbalance.qpl" from the project directory "GUI/testdata/qplprograms"
     Then the messages field should contain:
       |partial|
       |invalidbalance.qpl was successful|

features/load_an_assembled_qpo.feature

   As a researcher
   I want the program allow me to choose a "*.qpo" program and load it to the server so I can execute it.
 
+	Background:
+	  When I select "Load" from the "File" menu
+    And I load "coin.reference.qpo" from the project directory "GUI/testdata/qplprograms"
+    
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the main frame's title should be "Quantum Emulator - coin.reference.qpo"
     Then the button "Step" should appear
     Then the button "Go" should appear
     Then the frame "Quantum Stack" should be visible
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the messages field should contain:
       |partial|
       |loaded|
       |trimmed|
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the frame "Executing Code" should be visible
     When I click the button "Step" 1 time on the frame "Quantum Emulator"
     Then the selection on the frame "Executing Code" should show ---  1  Call 0 "cflip_fcdlbl0"
     Then the selection on the frame "Executing Code" should show ---  5  Measure "@q" 14 6 10
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the frame "Executing Code" should be visible
     When I click the button "Go" 1 time on the frame "Quantum Emulator"
     Then the selection on the frame "Executing Code" should show ---  3  DeScope
     Then the button "Step" on the frame "Quantum Emulator" should be disabled
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the frame "Classical Stack" should be visible
     Then the frame "Dump" should be visible
     Then the frame "Stack Translation" should be visible

features/show_and_hide_frames.feature

   As a researcher
   I want the program allow me to show only what i want.
 
+	Background:
+	  When I select "Load" from the "File" menu
+    And I load "coin.reference.qpo" from the project directory "GUI/testdata/qplprograms"
+
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the frame "Executing Code" should be visible
     When I select "Hide Executing Code" from the "View" menu
     Then the frame "Executing Code" should not be visible
 
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the frame "Stack Translation" should be visible
     When I select "Hide Stack Translation" from the "View" menu
     Then the frame "Stack Translation" should not be visible
 
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the frame "Dump" should be visible
     When I select "Hide Dump" from the "View" menu
     Then the frame "Dump" should not be visible
 
 
   Scenario:
-    When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
     Then the frame "Classical Stack" should be visible
     When I select "Hide Classical Stack" from the "View" menu
     Then the frame "Classical Stack" should not be visible

features/show_simulate_results.feature

 
   Background:
     When I select "Load" from the "File" menu
-    And I load "coin.reference.qpo" from the directory "testdata/qplprograms"
+    And I load "coin.reference.qpo" from the project directory "GUI/testdata/qplprograms"
 
   Scenario:
     When I click the button "Go" 1 time on the frame "Quantum Emulator"

features/step_definitions/compile_an_lqpl_program.rb

   menu_item =  $qe_frame.menu_item_with_path [menu, mitem].to_java(:string)
   menu_item.should_not be_nil
   menu_item.click()
-  sleep 0.5
+  sleep 0.25
 end
 
 
-And /^I load "([\w\.]*?\....)" from the directory "([\w\s\/]*)"$/ do |file, dir|
+And /^I load "([\w\.]*?\....)" from the project directory "([\w\s\/]*)"$/ do |file, dir|
 
-  fc = $qe_frame.file_chooser()
+  fc = JFileChooserFixture.new($robot) #   $qe_frame.file_chooser()
+
+  fc.select_file_in_project_directory(dir,file)
 
-  cdir =   Dir.getwd
-   
-   if not (cdir =~ /GUI/)
-     cdir = java.io.File.new(cdir,"GUI")
-     fc.set_current_directory(cdir)
-     sleep 0.1
-   end
-   
-   dirs = dir.split("/")
-   dirs.each do |d|
-     cdir = java.io.File.new(cdir, d)
-     fc.set_current_directory (cdir)
-     sleep 0.1
-   end
-  # Above is right way....
-  
-  # cdir =  "/Users/gilesb/programming/mixed/lqpl/GUI/testdata/qplprograms"
-  #  fc.set_current_directory (java.io.File.new cdir)
-  #  sleep 0.25
- 
-  sel_file = java.io.File.new(cdir,file)
-  sleep 0.25
-  fc.select_file sel_file
-  sleep 0.25
   fc.approve
 
 end
 
 
-Then /^"([\w\s]*?\.qpo)" should be created in "([\w\s\/]*)" and be equal to "([\w\s\.]*?\.qpo)"$/ do |outfile, outdir,reference|
-  topdir = Dir.getwd
-  if not (topdir =~ /GUI/)
-    topdir = topdir + "/GUI"
-  end
-  realdir = topdir + "/" +outdir
-  theFile = realdir + "/" + outfile
-  sleep_until(10) {File.exist?(theFile)}
-  # tries = 0
-  #   while tries < 10 do # wait up to 2.5 seconds for compile to finish
-  #     sleep 0.25
-  #     break if File.exist?(theFile)
-  #     tries += 1
-  #   end
-  File.exist?(realdir + "/" + outfile).should be_true
-  File.open(realdir + "/" + outfile) do |newone|
-    result = newone.read
-    File.open(realdir + "/" + reference) do |ref|
-      refvalue = ref.read
-      result.should == refvalue
-    end
-  end
+Then /^"([\w\s]*?\.qpo)" should be created in the project directory "([\w\s\/]*)" and be equal to "([\w\s\.]*?\.qpo)"$/ do |outfile, outdir,reference|
+  the_file = File.file_in_project_subdir(outdir, outfile)
+  
+  sleep_until_file_exists(10,the_file).should be_true
+  
+  File.read(the_file).should == File.read(File.file_in_project_subdir(outdir,reference))
 end
 
 Then /^the messages field should contain:$/ do |client_message_table|
-  theTextArea = JTextComponentFixture.new($robot,"messagesTextArea")
-  message_texts = client_message_table.hashes.collect {|h| Regexp.new h.values[0]}
-  message_texts.each do |t|
-    theTextArea.text.should =~ t
-  end
-
+  all_text_is_in_text_component(client_message_table, JTextComponentFixture.new($robot,"messagesTextArea"))
 end

features/step_definitions/load_an_assembled_qpo.rb

   theSpinner.text.should == "#{spin_value}"
 end
 
-Then /^the frame "([\w\s]*)" should (not )?be visible$/ do |frame_title,visible|
-   # set_frame_ref_var(frame_title)
-   # frame_fixture = eval(frame_ref_var_string frame_title)
-   frame_fixture = set_and_return_frame_fixture(frame_title)
-   if visible == 'not '
-     sleep_until(5) {!frame_fixture.edt_visible?}
-     # tries=0
-     #      while tries < 5 do
-     #        sleep 0.25
-     #        break if !frame_fixture.visible?
-     #      end
-     frame_fixture.should_not be_edt_visible
-   else
-     sleep_until(5) {frame_fixture.edt_visible?}
-     frame_fixture.should be_edt_visible
-   end
+Then /^the frame "([\w\s]*)" should (be|not be) visible$/ do |frame_title,visible|
+  frame_fixture = set_and_return_frame_fixture(frame_title)
+  sleep_until_visibility(5,frame_fixture,visible).should be_true
 end
 
 Then /^I click the spinner "([\w\s]*)" (up|down) (\d)* times? on the frame "([\w\s]*)"$/ do |spinner_label, direction, count, frame_title|

features/step_definitions/show_simulate_results.rb

 Then /^the dialog "([\w\s]*)" should have one of:$/ do |dialog_title, message_text_table|
   # table is a Cucumber::Ast::Table
   dialog_fixture = WindowFinder.find_dialog(DialogMatcher.with_title (dialog_title)).using($robot)
-  the_display_area_label = dialog_fixture.label(JLabelMatcher.with_text(Pattern.compile("<html>.*html>")))
-  message_text = message_text_table.hashes.collect {|h| h.values[0]} # just the list of values
+  the_display_area_label = dialog_fixture.label(label_matcher_with_pattern("<html>.*html>"))
   
-  message_texts = message_text_table.hashes.collect {|h| Regexp.new h.values[0]}
-  message_shown = message_texts.any? do |t|
-    the_display_area_label.text =~ t
-  end
-  message_shown.should == true
+  any_text_is_in_text_component(message_text_table, the_display_area_label).should be_true
   
-  the_button = dialog_fixture.button()
-  the_button.click
+  dialog_fixture.button().click
 end

features/support/component_query.rb

   end
 end
 
-class VisibleQuery < ComponentQuery
+class OwnerQuery < ComponentQuery
   
   def executeInEDT
-    @component.is_visible
+    @component.owner
   end
 end
 
+
 class EnabledQuery < ComponentQuery
   
   def executeInEDT
   end
 end
 
+class SelectedTextQuery < ComponentQuery
+  
+  def executeInEDT
+    @component.selected_text
+  end
+end
 
 class ViewportQuery < ComponentQuery
   
   end
 end
 
-class SelectedTextQuery < ComponentQuery
+class VisibleQuery < ComponentQuery
   
   def executeInEDT
-    @component.selected_text
+    @component.is_visible
   end
 end
 
     return GuiActionRunner.execute(LabelForQuery.new(self))
   end
   
+  def edt_owner
+    return GuiActionRunner.execute(OwnerQuery.new(self))
+  end
+    
   def edt_selected_text
     return GuiActionRunner.execute(SelectedTextQuery.new(self))
   end

features/support/component_searches.rb

 module ComponentSearches
-  def check_component_contains_label(container,message_text)
-    found = false
-    container.components.each do |comp|
-      case comp
-      when javax.swing.JLabel then
-        found |= message_text.any? {|mt| comp.text =~ Regexp.new(mt)}
-      when java.awt.Container then
-        found |= check_component_contains_label(comp,message_text)
-      end
-    end
-    found
-  end
+
   def spinner_for_label(label_text,frm=$qe_frame)
     theLabel = frm.label(JLabelMatcher.with_text label_text)
     theLabel.should_not == nil
     label_for = theLabel.edt_label_for
     JSpinnerFixture.new($robot,label_for) 
   end
+  
+  def all_text_is_in_text_component(message_table,text_fixture)
+    message_table.hashes.collect {|h| Regexp.new h.values[0]}.each do |t|
+      text_fixture.text.should =~ t
+    end
+  end
+  
+  def any_text_is_in_text_component(message_table,text_fixture)
+    message_texts = message_table.hashes.collect {|h| Regexp.new h.values[0]}
+    message_texts.any? do |t|
+      text_fixture.text =~ t
+    end
+  end
+  
 end
 
 World(ComponentSearches)

features/support/env.rb

 if not (defined? RUBY_ENGINE && RUBY_ENGINE == 'jruby')
   abort 'Sorry - Feature tests of LQPL requires JRuby. You appear to be running or defaulted to some other ruby engine.'
 end
+
 where_i_am = File.expand_path(File.dirname(__FILE__))
+$project_dir = where_i_am +"/../../"
+
 %w{src lqpl_gui lib/java lib/ruby devlib/java}.each do |dir|
   $LOAD_PATH << where_i_am+"/../../GUI/"+ dir
 end
 ENV['PATH'] = "#{where_i_am + '/../../out/bin'}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
 
 java.lang.System.set_property("apple.laf.useScreenMenuBar", "false")
-java.lang.System.set_property("com.drogar.testing.jemmy","true")
+java.lang.System.set_property("com.drogar.testing.fest","true")
 
 require 'manifest'
 
   java_import "org.fest.swing.edt."+c
 end
 
-%w{WindowFinder}.each do |c|
-  java_import "org.fest.swing.finder."+c
+%w{Window}.each do |c|
+  java_import "org.fest.swing.finder."+c+"Finder"
 end
 
-%w{ComponentFixture JMenuItemFixture FrameFixture JTextComponentFixture JSpinnerFixture JLabelFixture JButtonFixture}.each do |c|
-  java_import "org.fest.swing.fixture."+c
+%w{Component JMenuItem Frame JTextComponent JSpinner JLabel JButton JFileChooser}.each do |c|
+  java_import "org.fest.swing.fixture."+c+"Fixture"
 end
 
-%w{JButtonMatcher JLabelMatcher FrameMatcher DialogMatcher}.each do |c|
-  java_import "org.fest.swing.core.matcher."+c
+%w{JButton JLabel Frame Dialog}.each do |c|
+  java_import "org.fest.swing.core.matcher."+c+"Matcher"
 end
 
 java_import java.util.regex.Pattern
 
 java_import java.awt.Component
 
-java_import javax.swing.JButton
-
-java_import java.awt.event.InputEvent
-java_import java.awt.event.KeyEvent
 
+require 'support/component_query'
 
 
 class AppStarter < GuiQuery
 
 
 # consider starting up servers now and dropping during at_exit.
-# Around do |sc, blk|
-# 
-#   runner = GuiActionRunner.execute(AppStarter.new)
-#   $robot = BasicRobot.robot_with_current_awt_hierarchy
-#   $qe_frame = FrameFixture.new($robot, "Quantum Emulator")
-#   blk.call
-#   $robot.press_modifiers(InputEvent::META_MASK)
-#   $robot.press_key(KeyEvent::VK_Q)
-#   $robot.release_key(KeyEvent::VK_Q)
-# #  $qe_frame.close
-#   
-#   $robot.clean_up
-#   $robot = nil
-# 
-#   $qe_frame = nil
-#   #LqplController.instance.close
-#   runner = nil
-#   sleep 2
-# end
 
 runner = GuiActionRunner.execute(AppStarter.new)
 $robot = BasicRobot.robot_with_current_awt_hierarchy
 $qe_frame = FrameFixture.new($robot, "Quantum Emulator")
-
+#$owner = FrameFixture.new($robot,$qe_frame.edt_owner)
 
 at_exit {
   

features/support/file_manipulation.rb

+class JFileChooserFixture
+ def set_to_project_sub_directory(dir_string)
+   cdir = Dir.getwd
+   dirs = dir_string.split("/")
+   dirs.each do |d|
+     cdir = java.io.File.new(cdir, d)
+     set_current_directory (cdir)
+     sleep 0.1
+   end
+   cdir
+ end
+ 
+ def select_file_in_project_directory(dir_string, file_name)
+   pdir = set_to_project_sub_directory(dir_string)
+   select_file(java.io.File.new(pdir,file_name))
+ end
+end
+
+class File
+  def self.file_in_project_subdir(subdir,file)
+    File.join(Dir.getwd,subdir,file)
+  end
+end

features/support/fixture_matches.rb

+module FixtureMatchers
+  def label_matcher_with_pattern(p)
+    JLabelMatcher.with_text(Pattern.compile(p))
+  end
+end
+
+World(FixtureMatchers)

features/support/hooks.rb

+# 
+# Before do
+# 
+# end
+# 
+# After do
+# end
 
-Before do
+# TODO - reconsider trying this (Around) again if there is a way to cleanly stop / start the 
+# system while testing.
+#
+# java_import java.awt.event.InputEvent
+# java_import java.awt.event.KeyEvent
 
-end
-
-After do
-end
+# Around do |sc, blk|
+# 
+#   runner = GuiActionRunner.execute(AppStarter.new)
+#   $robot = BasicRobot.robot_with_current_awt_hierarchy
+#   $qe_frame = FrameFixture.new($robot, "Quantum Emulator")
+#   blk.call
+#   $robot.press_modifiers(InputEvent::META_MASK)
+#   $robot.press_key(KeyEvent::VK_Q)
+#   $robot.release_key(KeyEvent::VK_Q)
+# #  $qe_frame.close
+#   
+#   $robot.clean_up
+#   $robot = nil
+# 
+#   $qe_frame = nil
+#   #LqplController.instance.close
+#   runner = nil
+#   sleep 2
+# end

features/support/race_conditions.rb

     count = 0
     while count < tries
       sleep 0.25
-      break if condition.call
+      return true if condition.call
       count += 1
     end
+    return false
+  end
+  
+  def sleep_until_not(tries, &condition)
+    sleep_until(tries) {!condition.call}
+  end
+  
+  def sleep_until_file_exists(tries,file_name)    
+    sleep_until(tries) {File.exist?(file_name)}
+  end
+  
+  def sleep_until_visibility(tries,component,condition)
+    sleep_until(tries) {component.edt_visible? == condition}
   end
 end
 

features/support/transforms.rb

+Transform /^be|not be$/ do |s|
+  s == 'be'
+end