teuton 2.1.8 → 2.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -8
  3. data/bin/check_teuton +43 -0
  4. data/docs/changelog/contributions.md +32 -0
  5. data/docs/changelog/v2.1.md +22 -0
  6. data/docs/changelog/v2.2.md +29 -0
  7. data/docs/commands/README.md +105 -7
  8. data/docs/commands/example_check.md +54 -0
  9. data/docs/commands/example_run.md +112 -0
  10. data/docs/dsl/README.md +11 -9
  11. data/docs/dsl/definition/expect.md +25 -21
  12. data/docs/dsl/definition/group.md +5 -1
  13. data/docs/dsl/definition/result.md +45 -34
  14. data/docs/dsl/definition/run_local.md +34 -0
  15. data/docs/dsl/definition/run_remote.md +119 -0
  16. data/docs/dsl/definition/target.md +6 -0
  17. data/docs/dsl/execution/export.md +27 -19
  18. data/docs/dsl/execution/play.md +4 -0
  19. data/docs/dsl/execution/send.md +21 -2
  20. data/docs/dsl/execution/show.md +13 -8
  21. data/docs/dsl/setting/get.md +24 -8
  22. data/docs/dsl/setting/set.md +8 -3
  23. data/docs/install/README.md +19 -26
  24. data/docs/install/modes_of_use.md +27 -26
  25. data/docs/install/scripts.md +53 -36
  26. data/docs/install/vagrant_docker.md +56 -0
  27. data/docs/learn/README.md +13 -6
  28. data/docs/learn/example-01-target.md +78 -61
  29. data/docs/learn/example-02-config.md +152 -0
  30. data/docs/learn/example-03-remote-hosts.md +31 -25
  31. data/docs/learn/example-04-use.md +23 -17
  32. data/docs/learn/example-05-debug.md +24 -17
  33. data/docs/learn/example-06-log.md +70 -0
  34. data/lib/teuton/application.rb +7 -4
  35. data/lib/teuton/case_manager/case/case.rb +4 -1
  36. data/lib/teuton/case_manager/case/dsl/expect.rb +3 -1
  37. data/lib/teuton/case_manager/case/dsl/goto.rb +12 -7
  38. data/lib/teuton/case_manager/case/dsl/macro.rb +38 -0
  39. data/lib/teuton/case_manager/case/dsl/main.rb +1 -2
  40. data/lib/teuton/case_manager/case/dsl/target.rb +1 -1
  41. data/lib/teuton/case_manager/case/runner.rb +7 -7
  42. data/lib/teuton/case_manager/case_manager.rb +1 -20
  43. data/lib/teuton/case_manager/check_cases.rb +12 -2
  44. data/lib/teuton/case_manager/dsl.rb +4 -6
  45. data/lib/teuton/case_manager/export_manager.rb +29 -3
  46. data/lib/teuton/case_manager/report.rb +29 -8
  47. data/lib/teuton/case_manager/show.rb +8 -4
  48. data/lib/teuton/cli.rb +1 -0
  49. data/lib/teuton/cli/play.rb +1 -0
  50. data/lib/teuton/cli/version.rb +1 -4
  51. data/lib/teuton/files/config.yaml +0 -1
  52. data/lib/teuton/files/start.rb +1 -1
  53. data/lib/teuton/files/template/case.html +135 -0
  54. data/lib/teuton/files/template/resume.html +115 -0
  55. data/lib/teuton/project/laboratory/builtin.rb +2 -1
  56. data/lib/teuton/project/laboratory/dsl.rb +13 -15
  57. data/lib/teuton/project/laboratory/laboratory.rb +5 -1
  58. data/lib/teuton/project/laboratory/show.rb +21 -13
  59. data/lib/teuton/project/name_file_finder.rb +6 -1
  60. data/lib/teuton/project/project.rb +7 -3
  61. data/lib/teuton/project/readme/dsl.rb +3 -1
  62. data/lib/teuton/project/readme/readme.rb +37 -26
  63. data/lib/teuton/project/skeleton.rb +20 -4
  64. data/lib/teuton/report/close.rb +15 -11
  65. data/lib/teuton/report/formatter/formatter_factory.rb +10 -6
  66. data/lib/teuton/report/formatter/html_formatter.rb +16 -79
  67. data/lib/teuton/report/formatter/resume_html_formatter.rb +39 -0
  68. data/lib/teuton/report/formatter/resume_yaml_formatter.rb +7 -1
  69. data/lib/teuton/report/report.rb +5 -4
  70. data/lib/teuton/report/show.rb +55 -26
  71. metadata +26 -39
  72. data/docs/changelog/todo.md +0 -46
  73. data/docs/commands/create_skeleton.md +0 -31
  74. data/docs/commands/help.md +0 -13
  75. data/docs/commands/revise_test.md +0 -46
  76. data/docs/commands/run_test_unit.md +0 -78
  77. data/docs/commands/show_version.md +0 -9
  78. data/docs/developers/01-telnet.md +0 -121
  79. data/docs/developers/02-ssh.md +0 -93
  80. data/docs/developers/03-encoding.md +0 -153
  81. data/docs/developers/comparative.md +0 -17
  82. data/docs/dsl/_Sidebar.md +0 -30
  83. data/docs/dsl/definition/goto.md +0 -112
  84. data/docs/dsl/definition/run.md +0 -23
  85. data/docs/install/tested_os.md +0 -25
  86. data/docs/install/vagrant.md +0 -9
  87. data/docs/learn/example-02-configfile.md +0 -174
  88. data/docs/learn/quick-demo.md +0 -170
  89. data/lib/teuton/case_manager/case/dsl/check.rb +0 -24
  90. data/lib/teuton/case_manager/case/dsl/missing.rb +0 -12
  91. data/lib/teuton/files/gitignore +0 -2
@@ -55,10 +55,8 @@ class CaseManager
55
55
  puts ' Usage: export :format => :colored_text'
56
56
  raise '[ERROR] CaseManager#export: Argument error!'
57
57
  end
58
- # First: export files
58
+ # Export report files
59
59
  ExportManager.run(@report, @cases, args)
60
- # Second: preserve files if required
61
- preserve_files if args[:preserve] == true
62
60
  end
63
61
 
64
62
  ##
@@ -71,21 +69,4 @@ class CaseManager
71
69
  @cases.each { |c| threads << Thread.new { c.send(args) } }
72
70
  threads.each(&:join)
73
71
  end
74
-
75
- private
76
-
77
- ##
78
- # Preserve output files for current project
79
- def preserve_files
80
- app = Application.instance
81
- t = Time.now
82
- subdir = "#{t.year}#{format('%02d',t.month)}#{format('%02d',t.day)}-" \
83
- "#{format('%02d',t.hour)}#{format('%02d',t.min)}" \
84
- "#{format('%02d',t.sec)}"
85
- logdir = File.join(app.output_basedir, app.global[:tt_testname], subdir)
86
- srcdir = File.join(app.output_basedir, app.global[:tt_testname])
87
- puts "[INFO] Preserving files => #{logdir}"
88
- FileUtils.mkdir(logdir)
89
- Dir.glob(File.join(srcdir, '**.*')).each { |file| FileUtils.cp(file, logdir) }
90
- end
91
72
  end
@@ -5,6 +5,8 @@
5
5
  class CaseManager
6
6
  private
7
7
 
8
+ ##
9
+ # Start checking every single case
8
10
  def check_cases!
9
11
  app = Application.instance
10
12
 
@@ -33,14 +35,16 @@ class CaseManager
33
35
  close_main_report(start_time)
34
36
  end
35
37
 
38
+ ##
39
+ # Run all cases
36
40
  def run_all_cases
37
41
  start_time = Time.now
38
42
  if Application.instance.global[:tt_sequence]
39
- verboseln "[INFO] Running in sequence (#{start_time})"
43
+ verboseln Rainbow("[INFO] Running in sequence (#{start_time})").yellow.bright
40
44
  # Run every case in sequence
41
45
  @cases.each(&:play)
42
46
  else
43
- verboseln "[INFO] Running in parallel (#{start_time})"
47
+ verboseln Rainbow("[INFO] Running in parallel (#{start_time})").yellow.bright
44
48
  threads = []
45
49
  # Run all cases in parallel
46
50
  @cases.each { |c| threads << Thread.new { c.play } }
@@ -49,6 +53,8 @@ class CaseManager
49
53
  start_time
50
54
  end
51
55
 
56
+ ##
57
+ # Collect uniques values for all cases
52
58
  def collect_uniques_for_all_cases
53
59
  uniques = {} # Collect "unique" values from all cases
54
60
  @cases.each do |c|
@@ -63,6 +69,10 @@ class CaseManager
63
69
  uniques
64
70
  end
65
71
 
72
+ ##
73
+ # 1) Reevaluate every case with collected unique values
74
+ # 2) Close all case reports
75
+ # 3) And order to build hall of fame
66
76
  def close_reports_for_all_cases(uniques)
67
77
  threads = []
68
78
  @cases.each { |c| threads << Thread.new { c.close uniques } }
@@ -12,13 +12,11 @@ def use(filename)
12
12
  app.uses << File.basename(findfiles.first)
13
13
  end
14
14
 
15
- def define_check(name, *args, &block)
16
- Application.instance.checks[name] = { args: args, block: block }
15
+ def define_macro(name, *args, &block)
16
+ Application.instance.macros[name] = { args: args, block: block }
17
17
  end
18
- alias definecheck define_check
19
- alias def_check define_check
20
- alias defcheck define_check
21
- alias dcheck define_check
18
+ alias def_macro define_macro
19
+ alias defmacro define_macro
22
20
 
23
21
  def group(name, &block)
24
22
  Application.instance.groups << { name: name, block: block }
@@ -3,24 +3,50 @@
3
3
  require_relative '../application'
4
4
 
5
5
  ##
6
- # ExportManager is used by CaseManager to export output reports)
6
+ # ExportManager is used by CaseManager to export output reports
7
7
  module ExportManager
8
8
  ##
9
9
  # Run export function
10
10
  # @param main_report (Report)
11
11
  # @param cases (Array)
12
12
  # @param args (Hash) Selected export options
13
+ # rubocop: disable Metrics/AbcSize
13
14
  def self.run(main_report, cases, args)
14
15
  # default :mode=>:all, :format=>:txt
15
16
  format = args[:format] || Application.instance.default[:format]
16
17
  mode = args[:mode] || :all
17
- # Export case reports
18
+ # Step 1: Export case reports
18
19
  if %i[details all].include? mode
19
20
  threads = []
20
21
  cases.each { |c| threads << Thread.new { c.export format } }
21
22
  threads.each(&:join)
22
23
  end
23
- # Export resume report
24
+ # Step 2: Export resume report
24
25
  main_report.export_resume format if %i[resume all].include? mode
26
+ # Step 3: Preserve files if required
27
+ preserve_files if args[:preserve] == true
25
28
  end
29
+ # rubocop:enable Metrics/AbcSize
30
+
31
+ ##
32
+ # Preserve output files for current project
33
+ # rubocop:disable Metrics/AbcSize
34
+ # rubocop:disable Metrics/MethodLength
35
+ # rubocop:disable Layout/LineLength
36
+ private_class_method def self.preserve_files
37
+ app = Application.instance
38
+ t = Time.now
39
+ data = { year: t.year, month: t.month, day: t.day,
40
+ hour: t.hour, min: t.min, sec: t.sec }
41
+ subdir = format('%<year>s%<month>02d%<day>02d-' \
42
+ '%<hour>02d%<min>02d%<sec>02d', data)
43
+ logdir = File.join(app.output_basedir, app.global[:tt_testname], subdir)
44
+ srcdir = File.join(app.output_basedir, app.global[:tt_testname])
45
+ puts "[INFO] Preserving files => #{logdir}"
46
+ FileUtils.mkdir(logdir)
47
+ Dir.glob(File.join(srcdir, '**.*')).each { |file| FileUtils.cp(file, logdir) }
48
+ end
49
+ # rubocop:enable Metrics/AbcSize
50
+ # rubocop:enable Metrics/MethodLength
51
+ # rubocop:enable Layout/LineLength
26
52
  end
@@ -1,21 +1,28 @@
1
-
1
+ require 'rainbow'
2
+ ##
3
+ # Class CaseManager
4
+ # Methods related with report
2
5
  class CaseManager
3
6
 
4
7
  private
5
8
 
6
- def open_main_report(p_config_filename)
9
+ ##
10
+ # Open main report (resume report)
11
+ # @param config_filepath (String)
12
+ def open_main_report(config_filepath)
7
13
  app = Application.instance
8
14
 
9
15
  @report.head[:tt_title] = "Executing [#{app.name}] (version #{Application::VERSION})"
10
- @report.head[:tt_scriptname] = app.script_path
11
- @report.head[:tt_configfile] = p_config_filename
16
+ @report.head[:tt_scriptname] = trim(app.script_path)
17
+ @report.head[:tt_configfile] = trim(config_filepath)
18
+ @report.head[:tt_pwd] = app.running_basedir
12
19
  @report.head[:tt_debug] = true if @debug
13
- # @report.head[:tt_uses] = app.uses.join(', ')
20
+ # @report.head[:tt_uses] = app.uses.join(', ') # TO-REVISE
14
21
  @report.head.merge!(app.global)
15
22
 
16
23
  verboseln ' '
17
24
  verboseln '=' * @report.head[:tt_title].length
18
- verboseln @report.head[:tt_title]
25
+ verboseln Rainbow(@report.head[:tt_title]).yellow.bright
19
26
  end
20
27
 
21
28
  def close_main_report(start_time)
@@ -24,8 +31,8 @@ class CaseManager
24
31
  @report.tail[:finish_time] = finish_time
25
32
  @report.tail[:duration] = finish_time - start_time
26
33
 
27
- verbose "\n[INFO] Duration = #{format('%3.3f',(finish_time - start_time))}"
28
- verboseln " (#{finish_time})"
34
+ verbose Rainbow("\n[INFO] Duration = #{format('%3.3f',(finish_time - start_time))}").yellow.bright
35
+ verboseln Rainbow(" (#{finish_time})").yellow.bright
29
36
  verboseln '=' * @report.head[:tt_title].length
30
37
  verboseln ' '
31
38
 
@@ -49,4 +56,18 @@ class CaseManager
49
56
  @report.lines << line
50
57
  end
51
58
  end
59
+
60
+ ##
61
+ # Trim string text when is too long
62
+ # @param input (String)
63
+ # @return String
64
+ def trim(input)
65
+ return input unless input.to_s.start_with? Dir.pwd.to_s
66
+ return input if input == Dir.pwd.to_s
67
+
68
+ output = input.to_s
69
+ offset = (Dir.pwd).length + 1
70
+ output = "#{input[offset, input.size]}"
71
+ output.to_s
72
+ end
52
73
  end
@@ -2,19 +2,23 @@
2
2
 
3
3
  require_relative '../application'
4
4
 
5
- # CaseManager#show
5
+ # CaseManager show method
6
6
  class CaseManager
7
+ ##
8
+ # Show cases and resume report data on screep
9
+ # @param mode (Symbol) Values => :resume, :cases or :all
7
10
  def show(mode = :resume)
8
11
  return if Application.instance.quiet?
9
12
 
13
+ # Show resume report data on screen
10
14
  @report.show if %i[resume all].include? mode
11
15
 
12
- return unless %i[details all].include? mode
16
+ # Show cases report data on screen
17
+ return if mode == :resume
13
18
 
14
19
  @cases.each do |c|
15
- puts '____'
20
+ puts '=' * 40
16
21
  c.show
17
22
  end
18
- puts '.'
19
23
  end
20
24
  end
data/lib/teuton/cli.rb CHANGED
@@ -27,6 +27,7 @@ class CLI < Thor
27
27
  ##
28
28
  # These inputs are equivalents:
29
29
  # * teuton dir/foo
30
+ # * teuton run dir/foo
30
31
  # * teuton play dir/foo
31
32
  def method_missing(method, *_args, &_block)
32
33
  play(method.to_s)
@@ -7,6 +7,7 @@ class CLI < Thor
7
7
  option :cname, type: :string
8
8
  option :cpath, type: :string
9
9
  option :case, type: :string
10
+ option :color, type: :boolean
10
11
  option :quiet, type: :boolean
11
12
  desc '[run] [OPTIONS] DIRECTORY',
12
13
  'Run challenge from directory'
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rainbow'
4
-
5
3
  # Class method Teuton#version
6
4
  class CLI < Thor
7
5
  map ['v', '-v', '--version'] => 'version'
@@ -9,7 +7,6 @@ class CLI < Thor
9
7
  ##
10
8
  # Display version
11
9
  def version
12
- print Rainbow(Application::NAME).bright.blue
13
- puts ' (version ' + Rainbow(Application::VERSION).green + ')'
10
+ puts "#{Application::NAME} (version #{Application::VERSION})"
14
11
  end
15
12
  end
@@ -1,5 +1,4 @@
1
1
  ---
2
- :alias:
3
2
  :global:
4
3
  :cases:
5
4
  - :tt_members: MEMBERS
@@ -2,7 +2,7 @@
2
2
  group "GROUP NAME" do
3
3
 
4
4
  target "TARGET-1 DESCRIPTION"
5
- goto :localhost, :exec => "COMMAND-1"
5
+ run "COMMAND-1"
6
6
  expect "TEXT-1"
7
7
 
8
8
  end
@@ -0,0 +1,135 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <meta http-equiv="x-ua-compatible" content="IE=edge" />
7
+ <title>Teuton report</title>
8
+ <style>
9
+ body{margin:0;padding:0;font-family:sans-serif;font-size:12pt}a,a:visited,body{color:#303030}#content{padding-left:50px;padding-right:50px;padding-top:30px;padding-bottom:30px}#content h1{font-size:160%;margin-bottom:10px}#footer{margin-top:100px;font-size:80%;white-space:nowrap}#footer,#footer a{color:#a0a0a0}#line-wrapping-toggle{vertical-align:middle}#label-for-line-wrapping-toggle{vertical-align:middle}ul{margin-left:0}h1,h2,h3{white-space:nowrap}h2{font-size:120%}ul.tabLinks{padding-left:0;padding-top:10px;padding-bottom:10px;overflow:auto;min-width:800px;width:auto!important;width:800px}ul.tabLinks li{float:left;height:100%;list-style:none;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px;margin-bottom:0;-moz-border-radius:7px;border-radius:7px;margin-right:25px;border:solid 1px #d4d4d4;background-color:#f0f0f0}ul.tabLinks li:hover{background-color:#fafafa}ul.tabLinks li.selected{background-color:#00c21b;border-color:#00c21b}ul.tabLinks a{font-size:120%;display:block;outline:0;text-decoration:none;margin:0;padding:0}ul.tabLinks li h2{margin:0;padding:0}div.selected{display:block}div.deselected{display:none}div.tab table{min-width:350px;width:auto!important;width:350px;border-collapse:collapse}div.tab table,div.tab th{border-bottom:solid #d0d0d0 1px}div.tab th{text-align:left;white-space:nowrap;padding-left:6em}div.tab th:first-child{padding-left:0}div.tab td{white-space:nowrap;padding-left:6em;padding-top:5px;padding-bottom:5px}div.tab td:first-child{padding-left:0}div.tab td.numeric,div.tab th.numeric{text-align:right}span.code{display:inline-block;margin-top:0;margin-bottom:1em}span.code pre{font-size:11pt;padding-top:10px;padding-bottom:10px;padding-left:10px;padding-right:10px;margin:0;background-color:#f7f7f7;border:solid 1px #d0d0d0;min-width:700px;width:auto!important;width:700px}span.wrapped pre{word-wrap:break-word;white-space:pre-wrap;word-break:break-all}label.hidden{display:none}div.tab td.indentPath{padding-left:3em}
10
+ </style>
11
+ <script type="text/javascript">
12
+ !function(e,t){"use strict";var n={};function i(e,t){e.getAttribute("className")?e.setAttribute("className",t):e.setAttribute("class",t)}function s(e){return e.getAttribute("className")?e.getAttribute("className"):e.getAttribute("class")}function r(e,t){i(e,s(e)+" "+t)}function a(e,t){i(e,s(e).replace(t,""))}function l(){var e=t.getElementById("tabs");return n.tabs=function(e){return p(e,"DIV","tab")}(e),n.titles=function(e){for(var t=[],n=0;n<e.length;n++){var i=e[n],s=p(i,"H2",null)[0];s.parentNode.removeChild(s),s.innerText?t.push(s.innerText):t.push(s.textContent)}return t}(n.tabs),n.headers=function(e){var t=p(e,"UL","tabLinks");return p(t[0],"LI",null)}(e),n.select=b,n.deselectAll=g,n.select(0),!0}function d(){return t.getElementById("line-wrapping-toggle")}function h(){for(var e=t.getElementById("tabs").getElementsByTagName("span"),n=[],i=0;i<e.length;++i)e[i].className.indexOf("code")>=0&&n.push(e[i]);return n}function c(e){for(var t=h(),n=0;n<t.length;++n)e(t[n],"wrapped")}function o(){d().checked?c(r):c(a)}function u(){if(h().length>0){var e=d(),n=t.getElementById("label-for-line-wrapping-toggle");e.onclick=o,e.checked=!1,a(n,"hidden")}}function f(){for(var e=this.id.substr(1),t=0;t<n.tabs.length;t++)if(n.tabs[t].id===e){n.select(t);break}return!1}function b(e){for(this.deselectAll(),i(this.tabs[e],"tab selected"),i(this.headers[e],"selected");this.headers[e].firstChild;)this.headers[e].removeChild(this.headers[e].firstChild);var n=t.createElement("H2");n.appendChild(t.createTextNode(this.titles[e])),this.headers[e].appendChild(n)}function g(){for(var e=0;e<this.tabs.length;e++){for(i(this.tabs[e],"tab deselected"),i(this.headers[e],"deselected");this.headers[e].firstChild;)this.headers[e].removeChild(this.headers[e].firstChild);var n=t.createElement("A");n.setAttribute("id","ltab"+e),n.setAttribute("href","#tab"+e),n.onclick=f,n.appendChild(t.createTextNode(this.titles[e])),this.headers[e].appendChild(n)}}function p(e,t,n){for(var i=[],s=e.childNodes,r=0;r<s.length;r++){var a=s.item(r);if(1===a.nodeType&&a.nodeName===t){if(n&&a.className.indexOf(n)<0)continue;i.push(a)}}return i}e.onload=function(){l(),u()}}(window,window.document);
13
+ </script>
14
+ </head>
15
+
16
+ <body>
17
+ <div id="content">
18
+ <h1><img title="teuton logo" alt="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAFg0lEQVQ4T23UW0yTdxgG8Pf/9UQPtIUWKJSWciiDcj4VhRoZh9iZoAJDIZuJ2wUyxS3CdMvkZmOaLFtczDJ1ajaGTBxVNEQdYRoYKBRqWTkUKAiVcmoLBaQt/aCl36LJEi94r9/8rp7nQbDDBQQEsNL2pmVa55aPURm0fNzlCiQAnIggnjIYzKZTp052t9xqmVWpVHD23Nm0J0+fKCxTlta5ubkptBOYmp162IfO+DohPUkqCheTjIZpYLAYr1+9hpHxNbNp4eH95ntnFPkKWlhUeB0JYQVeL3HJtrF0eUcwPi2pRpYi+y5DISdZzUvQ19kDVCoVZClxAICg75+ezqyU3R8+G3gmDwwJviEUC/0n9AbdJnv7ox3BDIWikC/g3GRxfDkDPVowzy4AQRAgEAVDTEIsLC1ab40Pjn0WnRT7rihcVB8RHcmYmZ4x6XWjZTuCymJlht2+cRe8XtFgvw5wFw4UKgVCJaEgkUZ4V6zLF7W92jp5bla6v79fszRWyjMZTepdcRkf7AiWV5XHmI3WO7tzFXE26xK0NNwBUZgIio+VwtTYFD6i1dVqnmou5ynz4jEfyl1xRJjI9GLmd3XHs5odwTO1ZyKfa7XNBYeUqRgJg19/vA5BIUFw6Oj7MNj/7/r44FhNf7e6IasgR8ag+9zlC3iihZfzF7raO3/YEbxy5Yqk6d7tpvyD+3ax2CxoutYIfnx/2Fe0HzRdatvMlPHT3o7eZqVSKXOTPS1MNou/Zl2p7nrc1fg2iEpLSykAQDp9+jS9uramNjo+tjI+NYE+rBkEOpMBXJ4fdLd3Gv1E4hOP6pvaD5QfiHfYN1p8GD4U74bnk7YHbW2vQVTwcUGwTW8r2qJsp3ncHnoQO9C4OD/PQyTsSEJ6EidIKIDFuQUwz5hh3bZmo3IY3w50913LKzkQRSE8LTQ6baO8+EhFWUmZGlVWVgpbB9ouLmc5i9yxiAIYADblAVovQKRLDFwaF+bNs8BmciA2Kg5IGAmM81M2p9deJwwVGtftjp+pNNrsiHqw2mKxaNDB0oMJHTZ1szefEuNH5wJGIHARm7BqWwWejgm7SOkwt2CCQH4QhAQK3+TR6XLCqHHU5rS/WmWyWGGAoVWC2G6++tPVOlRRVRWjGlCpwmXh8WWpJcD3C4Ch8WFoGLoNpG0M0tyJYDYvAofNBR6XBw6nw0uhURAiA3ppNAKTyQJeIM8zazK1X/jmfAWqqKqIURlaVYx3fOOLA/aDLFQGTVoVaNeHIIwSCmXRRWAxWwBDCCxW69bw6LA2TCJh7ZZnysbHx0nmRTNIY6ItC8vztXwavxEdLToa30p7rLLnemL2TKeAjJDCL8I/gWCRIKojADLJKYC7NgHHXRAiDNmanjE2Oh32e75+nNyc7L0VBsM4k83lGNbWVo/fvH6zCyVHJGcYsueb8UJMkjESA1KbGP5IbwOMRobCyT2QjGKhr0fzehNgf6ES1h32kRcTkyeoGFWtf6E/TkLk86ny1PaHdx58MTk5OY3kcnnSWPDLBmcplshZYgB7ggom+SpBnQB3njUTZYSlUHRDg7CFb4JCoQDP9varv/5+9Lm6U92Qsy8nd8Y4Vy2Rii51POxoA4BtlPleJtu1uVkxHW05tZFNiAjci1jPMbO/nqFFFm8sh8WJCBIEmRFCZBzH+TabbYXB8f2qv6u3PjMnM0CeIo+sv1Gvt9vty68H802wExMTA3yEzMOTjJmTHo+bI14RfM8ms5yjutFzjnWHOEQc0u92u1nL5mUZiUzCA0MCuwCRfosUSe53dnbib4/0/9VD2dnZLDqXnoU7cKp+SN+VnJacNzEx8aXLhXMFwuA+18aGYH1lXerxeHy2vR5fKp1mE4tFJTqNTvM2+B9Df2VX8nqE4QAAAABJRU5ErkJggg==" />
19
+ Teuton report</h1>
20
+ <div id="header">
21
+ <p><b>Test name:</b> <%= config[:tt_testname] %></p>
22
+ <p><b>Members:</b> <%= config[:tt_members] %></p>
23
+ <p><b>Grade:</b> <%= results[:grade] %></p>
24
+ </div>
25
+ <div id="tabs">
26
+ <ul class="tabLinks">
27
+ <li><a href="#tab0">Config</a></li>
28
+ <li><a href="#tab1">Logs</a></li>
29
+ <li><a href="#tab2">Groups</a></li>
30
+ <li><a href="#tab3">Results</a></li>
31
+ <li><a href="#tab4">Hall of fame</a></li>
32
+ </ul>
33
+ <div class="tab" id="tab0">
34
+ <h2>Config</h2>
35
+ <table>
36
+ <thead>
37
+ <tr>
38
+ <th>Property</th>
39
+ <th class="numeric">Value</th>
40
+ </tr>
41
+ </thead>
42
+ <% config.each_pair do |key, value| %>
43
+ <tr>
44
+ <td><%= key.to_s %></td>
45
+ <td class="numeric"><%= value.to_s %></td>
46
+ </tr>
47
+ <% end %>
48
+ </table>
49
+ </div>
50
+ <div class="tab" id="tab1">
51
+ <h2>Logs</h2>
52
+ <% logs.each do |line| %>
53
+ <p><%= line %></p>
54
+ <% end %>
55
+ </div>
56
+ <div class="tab" id="tab2">
57
+ <h2>Groups</h2>
58
+ <% groups.each do |group| %>
59
+ <h2><%= group[:title] %></h2>
60
+ <table>
61
+ <thead>
62
+ <tr>
63
+ <th>Target</th>
64
+ <th>Property</th>
65
+ <th class="numeric">Value</th>
66
+ </tr>
67
+ </thead>
68
+ <% group[:targets].each do |target| %>
69
+ <tr>
70
+ <td><b><%= target[:description] %></b></td>
71
+ <td></td>
72
+ <td class="numeric"></td>
73
+ </tr>
74
+ <% target.each_pair do |key, value| %>
75
+ <% next if key == :description %>
76
+ <tr>
77
+ <td></td>
78
+ <td><%= key.to_s %></td>
79
+ <td class="numeric"><%= value.to_s %></td>
80
+ </tr>
81
+ <% end %>
82
+ <% end %>
83
+ <% end %>
84
+ </table>
85
+ <br/>
86
+ </div>
87
+ <div class="tab" id="tab3">
88
+ <h2>Results</h2>
89
+ <table>
90
+ <thead>
91
+ <tr>
92
+ <th>Property</th>
93
+ <th class="numeric">Value</th>
94
+ </tr>
95
+ </thead>
96
+ <% results.each_pair do |key, value| %>
97
+ <tr>
98
+ <td><%= key.to_s %></td>
99
+ <td class="numeric"><%= value.to_s %></td>
100
+ </tr>
101
+ <% end %>
102
+ </table>
103
+ </div>
104
+ <div class="tab" id="tab4">
105
+ <h2>Hall of fame</h2>
106
+ <table>
107
+ <thead>
108
+ <tr>
109
+ <th>Grade</th>
110
+ <th class="numeric">Cases</th>
111
+ </tr>
112
+ </thead>
113
+ <% hall_of_fame.each_pair do |key, value| %>
114
+ <tr>
115
+ <td><%= key.to_s %></td>
116
+ <td class="numeric"><%= value.to_s %></td>
117
+ </tr>
118
+ <% end %>
119
+ </table>
120
+ </div>
121
+ </div>
122
+ <div id="footer">
123
+ <p>
124
+ <div>
125
+ <label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
126
+ <input id="line-wrapping-toggle" type="checkbox" autocomplete="off" />
127
+ </label>
128
+ </div>
129
+ Generated by <a href="http://github.com/teuton-software/teuton">Teuton <%= version %></a>
130
+ at <%= results[:finish_time] %>
131
+ </p>
132
+ </div>
133
+ </div>
134
+ </body>
135
+ </html>
@@ -0,0 +1,115 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <meta http-equiv="x-ua-compatible" content="IE=edge" />
7
+ <title>Teuton report</title>
8
+ <style>
9
+ body{margin:0;padding:0;font-family:sans-serif;font-size:12pt}a,a:visited,body{color:#303030}#content{padding-left:50px;padding-right:50px;padding-top:30px;padding-bottom:30px}#content h1{font-size:160%;margin-bottom:10px}#footer{margin-top:100px;font-size:80%;white-space:nowrap}#footer,#footer a{color:#a0a0a0}#line-wrapping-toggle{vertical-align:middle}#label-for-line-wrapping-toggle{vertical-align:middle}ul{margin-left:0}h1,h2,h3{white-space:nowrap}h2{font-size:120%}ul.tabLinks{padding-left:0;padding-top:10px;padding-bottom:10px;overflow:auto;min-width:800px;width:auto!important;width:800px}ul.tabLinks li{float:left;height:100%;list-style:none;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px;margin-bottom:0;-moz-border-radius:7px;border-radius:7px;margin-right:25px;border:solid 1px #d4d4d4;background-color:#f0f0f0}ul.tabLinks li:hover{background-color:#fafafa}ul.tabLinks li.selected{background-color:#00c21b;border-color:#00c21b}ul.tabLinks a{font-size:120%;display:block;outline:0;text-decoration:none;margin:0;padding:0}ul.tabLinks li h2{margin:0;padding:0}div.selected{display:block}div.deselected{display:none}div.tab table{min-width:350px;width:auto!important;width:350px;border-collapse:collapse}div.tab table,div.tab th{border-bottom:solid #d0d0d0 1px}div.tab th{text-align:left;white-space:nowrap;padding-left:6em}div.tab th:first-child{padding-left:0}div.tab td{white-space:nowrap;padding-left:6em;padding-top:5px;padding-bottom:5px}div.tab td:first-child{padding-left:0}div.tab td.numeric,div.tab th.numeric{text-align:right}span.code{display:inline-block;margin-top:0;margin-bottom:1em}span.code pre{font-size:11pt;padding-top:10px;padding-bottom:10px;padding-left:10px;padding-right:10px;margin:0;background-color:#f7f7f7;border:solid 1px #d0d0d0;min-width:700px;width:auto!important;width:700px}span.wrapped pre{word-wrap:break-word;white-space:pre-wrap;word-break:break-all}label.hidden{display:none}div.tab td.indentPath{padding-left:3em}
10
+ </style>
11
+ <script type="text/javascript">
12
+ !function(e,t){"use strict";var n={};function i(e,t){e.getAttribute("className")?e.setAttribute("className",t):e.setAttribute("class",t)}function s(e){return e.getAttribute("className")?e.getAttribute("className"):e.getAttribute("class")}function r(e,t){i(e,s(e)+" "+t)}function a(e,t){i(e,s(e).replace(t,""))}function l(){var e=t.getElementById("tabs");return n.tabs=function(e){return p(e,"DIV","tab")}(e),n.titles=function(e){for(var t=[],n=0;n<e.length;n++){var i=e[n],s=p(i,"H2",null)[0];s.parentNode.removeChild(s),s.innerText?t.push(s.innerText):t.push(s.textContent)}return t}(n.tabs),n.headers=function(e){var t=p(e,"UL","tabLinks");return p(t[0],"LI",null)}(e),n.select=b,n.deselectAll=g,n.select(0),!0}function d(){return t.getElementById("line-wrapping-toggle")}function h(){for(var e=t.getElementById("tabs").getElementsByTagName("span"),n=[],i=0;i<e.length;++i)e[i].className.indexOf("code")>=0&&n.push(e[i]);return n}function c(e){for(var t=h(),n=0;n<t.length;++n)e(t[n],"wrapped")}function o(){d().checked?c(r):c(a)}function u(){if(h().length>0){var e=d(),n=t.getElementById("label-for-line-wrapping-toggle");e.onclick=o,e.checked=!1,a(n,"hidden")}}function f(){for(var e=this.id.substr(1),t=0;t<n.tabs.length;t++)if(n.tabs[t].id===e){n.select(t);break}return!1}function b(e){for(this.deselectAll(),i(this.tabs[e],"tab selected"),i(this.headers[e],"selected");this.headers[e].firstChild;)this.headers[e].removeChild(this.headers[e].firstChild);var n=t.createElement("H2");n.appendChild(t.createTextNode(this.titles[e])),this.headers[e].appendChild(n)}function g(){for(var e=0;e<this.tabs.length;e++){for(i(this.tabs[e],"tab deselected"),i(this.headers[e],"deselected");this.headers[e].firstChild;)this.headers[e].removeChild(this.headers[e].firstChild);var n=t.createElement("A");n.setAttribute("id","ltab"+e),n.setAttribute("href","#tab"+e),n.onclick=f,n.appendChild(t.createTextNode(this.titles[e])),this.headers[e].appendChild(n)}}function p(e,t,n){for(var i=[],s=e.childNodes,r=0;r<s.length;r++){var a=s.item(r);if(1===a.nodeType&&a.nodeName===t){if(n&&a.className.indexOf(n)<0)continue;i.push(a)}}return i}e.onload=function(){l(),u()}}(window,window.document);
13
+ </script>
14
+ </head>
15
+
16
+ <body>
17
+ <div id="content">
18
+ <h1><img title="teuton logo" alt="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAFg0lEQVQ4T23UW0yTdxgG8Pf/9UQPtIUWKJSWciiDcj4VhRoZh9iZoAJDIZuJ2wUyxS3CdMvkZmOaLFtczDJ1ajaGTBxVNEQdYRoYKBRqWTkUKAiVcmoLBaQt/aCl36LJEi94r9/8rp7nQbDDBQQEsNL2pmVa55aPURm0fNzlCiQAnIggnjIYzKZTp052t9xqmVWpVHD23Nm0J0+fKCxTlta5ubkptBOYmp162IfO+DohPUkqCheTjIZpYLAYr1+9hpHxNbNp4eH95ntnFPkKWlhUeB0JYQVeL3HJtrF0eUcwPi2pRpYi+y5DISdZzUvQ19kDVCoVZClxAICg75+ezqyU3R8+G3gmDwwJviEUC/0n9AbdJnv7ox3BDIWikC/g3GRxfDkDPVowzy4AQRAgEAVDTEIsLC1ab40Pjn0WnRT7rihcVB8RHcmYmZ4x6XWjZTuCymJlht2+cRe8XtFgvw5wFw4UKgVCJaEgkUZ4V6zLF7W92jp5bla6v79fszRWyjMZTepdcRkf7AiWV5XHmI3WO7tzFXE26xK0NNwBUZgIio+VwtTYFD6i1dVqnmou5ynz4jEfyl1xRJjI9GLmd3XHs5odwTO1ZyKfa7XNBYeUqRgJg19/vA5BIUFw6Oj7MNj/7/r44FhNf7e6IasgR8ag+9zlC3iihZfzF7raO3/YEbxy5Yqk6d7tpvyD+3ax2CxoutYIfnx/2Fe0HzRdatvMlPHT3o7eZqVSKXOTPS1MNou/Zl2p7nrc1fg2iEpLSykAQDp9+jS9uramNjo+tjI+NYE+rBkEOpMBXJ4fdLd3Gv1E4hOP6pvaD5QfiHfYN1p8GD4U74bnk7YHbW2vQVTwcUGwTW8r2qJsp3ncHnoQO9C4OD/PQyTsSEJ6EidIKIDFuQUwz5hh3bZmo3IY3w50913LKzkQRSE8LTQ6baO8+EhFWUmZGlVWVgpbB9ouLmc5i9yxiAIYADblAVovQKRLDFwaF+bNs8BmciA2Kg5IGAmM81M2p9deJwwVGtftjp+pNNrsiHqw2mKxaNDB0oMJHTZ1szefEuNH5wJGIHARm7BqWwWejgm7SOkwt2CCQH4QhAQK3+TR6XLCqHHU5rS/WmWyWGGAoVWC2G6++tPVOlRRVRWjGlCpwmXh8WWpJcD3C4Ch8WFoGLoNpG0M0tyJYDYvAofNBR6XBw6nw0uhURAiA3ppNAKTyQJeIM8zazK1X/jmfAWqqKqIURlaVYx3fOOLA/aDLFQGTVoVaNeHIIwSCmXRRWAxWwBDCCxW69bw6LA2TCJh7ZZnysbHx0nmRTNIY6ItC8vztXwavxEdLToa30p7rLLnemL2TKeAjJDCL8I/gWCRIKojADLJKYC7NgHHXRAiDNmanjE2Oh32e75+nNyc7L0VBsM4k83lGNbWVo/fvH6zCyVHJGcYsueb8UJMkjESA1KbGP5IbwOMRobCyT2QjGKhr0fzehNgf6ES1h32kRcTkyeoGFWtf6E/TkLk86ny1PaHdx58MTk5OY3kcnnSWPDLBmcplshZYgB7ggom+SpBnQB3njUTZYSlUHRDg7CFb4JCoQDP9varv/5+9Lm6U92Qsy8nd8Y4Vy2Rii51POxoA4BtlPleJtu1uVkxHW05tZFNiAjci1jPMbO/nqFFFm8sh8WJCBIEmRFCZBzH+TabbYXB8f2qv6u3PjMnM0CeIo+sv1Gvt9vty68H802wExMTA3yEzMOTjJmTHo+bI14RfM8ms5yjutFzjnWHOEQc0u92u1nL5mUZiUzCA0MCuwCRfosUSe53dnbib4/0/9VD2dnZLDqXnoU7cKp+SN+VnJacNzEx8aXLhXMFwuA+18aGYH1lXerxeHy2vR5fKp1mE4tFJTqNTvM2+B9Df2VX8nqE4QAAAABJRU5ErkJggg==" />
19
+ Teuton report</h1>
20
+ <div id="header">
21
+ <p><b>Test name:</b> <%= config[:tt_testname] %></p>
22
+ <p><b>Case number:</b> <%= cases.size %></p>
23
+ </div>
24
+ <div id="tabs">
25
+ <ul class="tabLinks">
26
+ <li><a href="#tab0">Config</a></li>
27
+ <li><a href="#tab1">Cases</a></li>
28
+ <li><a href="#tab2">Results</a></li>
29
+ <li><a href="#tab3">Hall of fame</a></li>
30
+ </ul>
31
+ <div class="tab" id="tab0">
32
+ <h2>Config</h2>
33
+ <table>
34
+ <thead>
35
+ <tr>
36
+ <th>Property</th>
37
+ <th class="numeric">Value</th>
38
+ </tr>
39
+ </thead>
40
+ <% config.each_pair do |key, value| %>
41
+ <tr>
42
+ <td><%= key.to_s %></td>
43
+ <td class="numeric"><%= value.to_s %></td>
44
+ </tr>
45
+ <% end %>
46
+ </table>
47
+ </div>
48
+ <div class="tab" id="tab1">
49
+ <h2>Cases</h2>
50
+ <table>
51
+ <thead>
52
+ <tr>
53
+ <th>Target</th>
54
+ <th>Property</th>
55
+ <th class="numeric">Value</th>
56
+ </tr>
57
+ </thead>
58
+ <% cases.each do |item| %>
59
+ <tr>
60
+ <td><b><%= item[:id] %></b></td>
61
+ <td><b><%= item[:members] %></b></td>
62
+ <td class="numeric"><%= item[:grade] %></td>
63
+ </tr>
64
+ <% end %>
65
+ </table>
66
+ <br/>
67
+ </div>
68
+ <div class="tab" id="tab2">
69
+ <h2>Results</h2>
70
+ <table>
71
+ <thead>
72
+ <tr>
73
+ <th>Property</th>
74
+ <th class="numeric">Value</th>
75
+ </tr>
76
+ </thead>
77
+ <% results.each_pair do |key, value| %>
78
+ <tr>
79
+ <td><%= key.to_s %></td>
80
+ <td class="numeric"><%= value.to_s %></td>
81
+ </tr>
82
+ <% end %>
83
+ </table>
84
+ </div>
85
+ <div class="tab" id="tab3">
86
+ <h2>Hall of fame</h2>
87
+ <table>
88
+ <thead>
89
+ <tr>
90
+ <th>Grade</th>
91
+ <th class="numeric">Cases</th>
92
+ </tr>
93
+ </thead>
94
+ <% hall_of_fame.each_pair do |key, value| %>
95
+ <tr>
96
+ <td><%= key.to_s %></td>
97
+ <td class="numeric"><%= value.to_s %></td>
98
+ </tr>
99
+ <% end %>
100
+ </table>
101
+ </div>
102
+ </div>
103
+ <div id="footer">
104
+ <p>
105
+ <div>
106
+ <label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
107
+ <input id="line-wrapping-toggle" type="checkbox" autocomplete="off" />
108
+ </label>
109
+ </div>
110
+ Generated by <a href="http://github.com/teuton-software/teuton">Teuton <%= version %></a> at <%= results[:finish_time] %>
111
+ </p>
112
+ </div>
113
+ </div>
114
+ </body>
115
+ </html>