stamina 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. data/CHANGELOG.md +22 -5
  2. data/LICENCE.md +2 -2
  3. data/bin/stamina +1 -7
  4. data/lib/stamina.rb +10 -19
  5. metadata +54 -333
  6. data/.gemtest +0 -0
  7. data/Gemfile +0 -2
  8. data/Gemfile.lock +0 -37
  9. data/Manifest.txt +0 -16
  10. data/README.md +0 -78
  11. data/Rakefile +0 -23
  12. data/example/adl/automaton.adl +0 -49
  13. data/example/adl/sample.adl +0 -53
  14. data/example/basic/characteristic_sample.adl +0 -32
  15. data/example/basic/target.adl +0 -9
  16. data/example/competition/31_test.adl +0 -1500
  17. data/example/competition/31_training.adl +0 -1759
  18. data/lib/stamina/abbadingo.rb +0 -2
  19. data/lib/stamina/abbadingo/random_dfa.rb +0 -48
  20. data/lib/stamina/abbadingo/random_sample.rb +0 -146
  21. data/lib/stamina/adl.rb +0 -298
  22. data/lib/stamina/automaton.rb +0 -1263
  23. data/lib/stamina/automaton/complete.rb +0 -36
  24. data/lib/stamina/automaton/equivalence.rb +0 -55
  25. data/lib/stamina/automaton/metrics.rb +0 -78
  26. data/lib/stamina/automaton/minimize.rb +0 -25
  27. data/lib/stamina/automaton/minimize/hopcroft.rb +0 -116
  28. data/lib/stamina/automaton/minimize/pitchies.rb +0 -64
  29. data/lib/stamina/automaton/strip.rb +0 -16
  30. data/lib/stamina/automaton/walking.rb +0 -363
  31. data/lib/stamina/classifier.rb +0 -52
  32. data/lib/stamina/command.rb +0 -45
  33. data/lib/stamina/command/abbadingo_dfa.rb +0 -81
  34. data/lib/stamina/command/abbadingo_samples.rb +0 -40
  35. data/lib/stamina/command/adl2dot.rb +0 -71
  36. data/lib/stamina/command/classify.rb +0 -48
  37. data/lib/stamina/command/help.rb +0 -27
  38. data/lib/stamina/command/infer.rb +0 -141
  39. data/lib/stamina/command/metrics.rb +0 -51
  40. data/lib/stamina/command/robustness.rb +0 -22
  41. data/lib/stamina/command/score.rb +0 -35
  42. data/lib/stamina/errors.rb +0 -23
  43. data/lib/stamina/ext/math.rb +0 -20
  44. data/lib/stamina/induction/blue_fringe.rb +0 -265
  45. data/lib/stamina/induction/commons.rb +0 -156
  46. data/lib/stamina/induction/rpni.rb +0 -186
  47. data/lib/stamina/induction/union_find.rb +0 -377
  48. data/lib/stamina/input_string.rb +0 -123
  49. data/lib/stamina/loader.rb +0 -1
  50. data/lib/stamina/markable.rb +0 -42
  51. data/lib/stamina/sample.rb +0 -267
  52. data/lib/stamina/scoring.rb +0 -213
  53. data/lib/stamina/utils.rb +0 -1
  54. data/lib/stamina/utils/decorate.rb +0 -81
  55. data/lib/stamina/version.rb +0 -14
  56. data/stamina.gemspec +0 -191
  57. data/stamina.noespec +0 -32
  58. data/tasks/debug_mail.rake +0 -78
  59. data/tasks/debug_mail.txt +0 -13
  60. data/tasks/gem.rake +0 -68
  61. data/tasks/spec_test.rake +0 -79
  62. data/tasks/unit_test.rake +0 -77
  63. data/tasks/yard.rake +0 -51
  64. data/test/stamina/abbadingo/random_dfa_test.rb +0 -16
  65. data/test/stamina/abbadingo/random_sample_test.rb +0 -78
  66. data/test/stamina/adl_test.rb +0 -516
  67. data/test/stamina/automaton/classifier_test.rb +0 -259
  68. data/test/stamina/automaton/complete_test.rb +0 -58
  69. data/test/stamina/automaton/equivalence_test.rb +0 -120
  70. data/test/stamina/automaton/metrics_test.rb +0 -36
  71. data/test/stamina/automaton/minimize/hopcroft_test.rb +0 -15
  72. data/test/stamina/automaton/minimize/minimize_test.rb +0 -55
  73. data/test/stamina/automaton/minimize/pitchies_test.rb +0 -15
  74. data/test/stamina/automaton/minimize/rice_edu_10.adl +0 -16
  75. data/test/stamina/automaton/minimize/rice_edu_10.min.adl +0 -13
  76. data/test/stamina/automaton/minimize/rice_edu_13.adl +0 -13
  77. data/test/stamina/automaton/minimize/rice_edu_13.min.adl +0 -7
  78. data/test/stamina/automaton/minimize/should_strip_1.adl +0 -8
  79. data/test/stamina/automaton/minimize/should_strip_1.min.adl +0 -6
  80. data/test/stamina/automaton/minimize/unknown_1.adl +0 -16
  81. data/test/stamina/automaton/minimize/unknown_1.min.adl +0 -12
  82. data/test/stamina/automaton/strip_test.rb +0 -36
  83. data/test/stamina/automaton/to_dot_test.rb +0 -64
  84. data/test/stamina/automaton/walking/dfa_delta_test.rb +0 -39
  85. data/test/stamina/automaton/walking_test.rb +0 -206
  86. data/test/stamina/automaton_additional_test.rb +0 -190
  87. data/test/stamina/automaton_test.rb +0 -1104
  88. data/test/stamina/exit.rb +0 -3
  89. data/test/stamina/induction/blue_fringe_test.rb +0 -83
  90. data/test/stamina/induction/induction_test.rb +0 -70
  91. data/test/stamina/induction/redblue_mergesamestatebug_expected.adl +0 -19
  92. data/test/stamina/induction/redblue_mergesamestatebug_pta.dot +0 -64
  93. data/test/stamina/induction/redblue_mergesamestatebug_sample.adl +0 -9
  94. data/test/stamina/induction/redblue_universal_expected.adl +0 -4
  95. data/test/stamina/induction/redblue_universal_sample.adl +0 -5
  96. data/test/stamina/induction/rpni_inria_expected.adl +0 -7
  97. data/test/stamina/induction/rpni_inria_sample.adl +0 -9
  98. data/test/stamina/induction/rpni_test.rb +0 -129
  99. data/test/stamina/induction/rpni_test_pta.dot +0 -22
  100. data/test/stamina/induction/rpni_universal_expected.adl +0 -4
  101. data/test/stamina/induction/rpni_universal_sample.adl +0 -4
  102. data/test/stamina/induction/union_find_test.rb +0 -124
  103. data/test/stamina/input_string_test.rb +0 -323
  104. data/test/stamina/markable_test.rb +0 -70
  105. data/test/stamina/randdfa.adl +0 -66
  106. data/test/stamina/sample.adl +0 -4
  107. data/test/stamina/sample_classify_test.rb +0 -149
  108. data/test/stamina/sample_test.rb +0 -290
  109. data/test/stamina/scoring_test.rb +0 -63
  110. data/test/stamina/small_dfa.dot +0 -16
  111. data/test/stamina/small_dfa.gif +0 -0
  112. data/test/stamina/small_nfa.dot +0 -18
  113. data/test/stamina/small_nfa.gif +0 -0
  114. data/test/stamina/stamina_test.rb +0 -80
  115. data/test/stamina/utils/decorate_test.rb +0 -65
  116. data/test/test_all.rb +0 -7
data/tasks/spec_test.rake DELETED
@@ -1,79 +0,0 @@
1
- # Installs a rake task for for running examples written using rspec.
2
- #
3
- # This file installs the 'rake spec_test' (aliased as 'rake spec') as well as
4
- # extends 'rake test' to run spec tests, if any. It is automatically generated
5
- # by Noe from your .noespec file, and should therefore be configured there,
6
- # under the variables/rake_tasks/spec_test entry, as illustrated below:
7
- #
8
- # variables:
9
- # rake_tasks:
10
- # spec_test:
11
- # pattern: spec/**/*_spec.rb
12
- # verbose: true
13
- # rspec_opts: [--color, --backtrace]
14
- # ...
15
- #
16
- # If you have specific needs requiring manual intervention on this file,
17
- # don't forget to set safe-override to false in your noe specification:
18
- #
19
- # template-info:
20
- # manifest:
21
- # tasks/spec_test.rake:
22
- # safe-override: false
23
- #
24
- # This file has been written to conform to RSpec v2.4.0. More information about
25
- # rspec and options of the rake task defined below can be found on
26
- # http://relishapp.com/rspec
27
- #
28
- begin
29
- require "rspec/core/rake_task"
30
- desc "Run RSpec code examples"
31
- RSpec::Core::RakeTask.new(:spec_test) do |t|
32
- # Glob pattern to match files.
33
- t.pattern = "spec/**/*_spec.rb"
34
-
35
- # By default, if there is a Gemfile, the generated command will include
36
- # 'bundle exec'. Set this to true to ignore the presence of a Gemfile,
37
- # and not add 'bundle exec' to the command.
38
- t.skip_bundler = false
39
-
40
- # Name of Gemfile to use
41
- t.gemfile = "Gemfile"
42
-
43
- # Whether or not to fail Rake when an error occurs (typically when
44
- # examples fail).
45
- t.fail_on_error = true
46
-
47
- # A message to print to stderr when there are failures.
48
- t.failure_message = nil
49
-
50
- # Use verbose output. If this is set to true, the task will print the
51
- # executed spec command to stdout.
52
- t.verbose = true
53
-
54
- # Use rcov for code coverage?
55
- t.rcov = false
56
-
57
- # Path to rcov.
58
- t.rcov_path = "rcov"
59
-
60
- # Command line options to pass to rcov. See 'rcov --help' about this
61
- t.rcov_opts = []
62
-
63
- # Command line options to pass to ruby. See 'ruby --help' about this
64
- t.ruby_opts = []
65
-
66
- # Path to rspec
67
- t.rspec_path = "rspec"
68
-
69
- # Command line options to pass to rspec. See 'rspec --help' about this
70
- t.rspec_opts = ["--color", "--backtrace"]
71
- end
72
- rescue LoadError => ex
73
- task :spec_test do
74
- abort 'rspec is not available. In order to run spec, you must: gem install rspec'
75
- end
76
- ensure
77
- task :spec => [:spec_test]
78
- task :test => [:spec_test]
79
- end
data/tasks/unit_test.rake DELETED
@@ -1,77 +0,0 @@
1
- # Installs a rake task for for running unit tests.
2
- #
3
- # This file installs the 'rake unit_test' and extends 'rake test' to run unit
4
- # tests, if any. It is automatically generated by Noe from your .noespec file,
5
- # and should therefore be configured there, under the variables/rake_tasks/unit_test
6
- # entry, as illustrated below:
7
- #
8
- # variables:
9
- # rake_tasks:
10
- # unit_test:
11
- # pattern: test/test*.rb
12
- # verbose: false
13
- # warning: false
14
- # ...
15
- #
16
- # If you have specific needs requiring manual intervention on this file,
17
- # don't forget to set safe-override to false in your noe specification:
18
- #
19
- # template-info:
20
- # manifest:
21
- # tasks/unit_test.rake:
22
- # safe-override: false
23
- #
24
- # More info about the TestTask and its options can be found on
25
- # http://rake.rubyforge.org/classes/Rake/TestTask.html
26
- #
27
- begin
28
- require 'rake/testtask'
29
- desc "Run unit tests"
30
- Rake::TestTask.new(:unit_test) do |t|
31
-
32
- # List of directories to added to $LOAD_PATH before running the
33
- # tests. (default is 'lib')
34
- t.libs = ["lib"]
35
-
36
- # True if verbose test output desired. (default is false)
37
- t.verbose = false
38
-
39
- # Test options passed to the test suite. An explicit TESTOPTS=opts
40
- # on the command line will override this. (default is NONE)
41
- t.options = nil
42
-
43
- # Request that the tests be run with the warning flag set.
44
- # E.g. warning=true implies "ruby -w" used to run the tests.
45
- t.warning = false
46
-
47
- # Glob pattern to match test files. (default is 'test/test*.rb')
48
- t.pattern = "test/test*.rb"
49
-
50
- # Style of test loader to use. Options are:
51
- #
52
- # * :rake -- Rake provided test loading script (default).
53
- # * :testrb -- Ruby provided test loading script.
54
- # * :direct -- Load tests using command line loader.
55
- #
56
- t.loader = :rake
57
-
58
- # Array of commandline options to pass to ruby when running test
59
- # loader.
60
- t.ruby_opts = []
61
-
62
- # Explicitly define the list of test files to be included in a
63
- # test. +list+ is expected to be an array of file names (a
64
- # FileList is acceptable). If both +pattern+ and +test_files+ are
65
- # used, then the list of test files is the union of the two.
66
- t.test_files = nil
67
-
68
- end
69
- rescue LoadError => ex
70
- task :unit_test do
71
- abort 'rspec is not available. In order to run spec, you must: gem install rspec'
72
- end
73
- ensure
74
- desc "Run all tests"
75
- task :test => [:unit_test]
76
- end
77
-
data/tasks/yard.rake DELETED
@@ -1,51 +0,0 @@
1
- # Installs a rake task to generate API documentation using yard.
2
- #
3
- # This file installs the 'rake yard' task. It is automatically generated by Noe from
4
- # your .noespec file, and should therefore be configured there, under the
5
- # variables/rake_tasks/yard entry, as illustrated below:
6
- #
7
- # variables:
8
- # rake_tasks:
9
- # yard:
10
- # files: lib/**/*.rb
11
- # options: []
12
- # ...
13
- #
14
- # If you have specific needs requiring manual intervention on this file,
15
- # don't forget to set safe-override to false in your noe specification:
16
- #
17
- # template-info:
18
- # manifest:
19
- # tasks/yard.rake:
20
- # safe-override: false
21
- #
22
- # This file has been written to conform to yard v0.6.4. More information about
23
- # yard and the rake task installed below can be found on http://yardoc.org/
24
- #
25
- begin
26
- require "yard"
27
- desc "Generate yard documentation"
28
- YARD::Rake::YardocTask.new(:yard) do |t|
29
- # Array of options passed to yardoc commandline. See 'yardoc --help' about this
30
- t.options = ["--output-dir", "doc/api", "-", "README.md", "CHANGELOG.md", "LICENCE.md"]
31
-
32
- # Array of ruby source files (and any extra documentation files
33
- # separated by '-')
34
- t.files = ["lib/**/*.rb"]
35
-
36
- # A proc to call before running the task
37
- # t.before = proc{ }
38
-
39
- # A proc to call after running the task
40
- # r.after = proc{ }
41
-
42
- # An optional lambda to run against all objects being generated.
43
- # Any object that the lambda returns false for will be excluded
44
- # from documentation.
45
- # t.verifier = lambda{|obj| true}
46
- end
47
- rescue LoadError
48
- task :yard do
49
- abort 'yard is not available. In order to run yard, you must: gem install yard'
50
- end
51
- end
@@ -1,16 +0,0 @@
1
- require 'stamina/stamina_test'
2
- require 'stamina/abbadingo'
3
- module Stamina
4
- module Abbadingo
5
- class RandomDFATest < StaminaTest
6
-
7
- def test_it_looks_ok_with_default_options
8
- dfa = RandomDFA.new(32).execute
9
- assert dfa.deterministic?
10
- assert dfa.minimal?
11
- assert dfa.complete?
12
- end
13
-
14
- end # class RandomDFATest
15
- end # module Abbadingo
16
- end # module Stamina
@@ -1,78 +0,0 @@
1
- require 'stamina/stamina_test'
2
- require 'stamina/abbadingo'
3
- module Stamina
4
- module Abbadingo
5
- class RandomSampleTest < StaminaTest
6
-
7
- def test_length_for
8
- rs = RandomSample::StringEnumerator.new
9
- assert_equal 0, rs.length_for(1)
10
- assert_equal 1, rs.length_for(2)
11
- assert_equal 1, rs.length_for(3)
12
- assert_equal 2, rs.length_for(4)
13
- assert_equal 2, rs.length_for(5)
14
- assert_equal 2, rs.length_for(6)
15
- assert_equal 2, rs.length_for(7)
16
- assert_equal 3, rs.length_for(8)
17
- end
18
-
19
- def test_string_for
20
- rs = RandomSample::StringEnumerator.new
21
- assert_equal [], rs.string_for(1)
22
- assert_equal ["0"], rs.string_for(2)
23
- assert_equal ["1"], rs.string_for(3)
24
- assert_equal ["0", "0"], rs.string_for(4)
25
- assert_equal ["1", "0"], rs.string_for(5)
26
- assert_equal ["0", "1"], rs.string_for(6)
27
- assert_equal ["1", "1"], rs.string_for(7)
28
- end
29
-
30
- def test_string_for_generates_all_diff
31
- rs = RandomSample::StringEnumerator.new
32
- h = {}
33
- (1..100).each{|i| h[rs.string_for(i)] = true}
34
- assert_equal 100, h.size
35
- end
36
-
37
- def test_string_for_respects_distribution
38
- rs = RandomSample::StringEnumerator.new
39
- lengths = Hash.new{|h,k| h[k] = 0}
40
- (1..127).each{|i| lengths[rs.string_for(i).size] += 1}
41
- assert_equal [0, 1, 2, 3, 4, 5, 6], lengths.keys.sort
42
- prop = (0..6).collect{|i| lengths[i].to_f/128}
43
- assert_equal [0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5], prop
44
- end
45
-
46
- def test_enumerator
47
- enum = RandomSample::StringEnumerator.new(10)
48
- lengths = Hash.new{|h,k| h[k] = 0}
49
- 20000.times{lengths[enum.one.size] += 1}
50
- assert (lengths.keys.sort - (0..10).to_a).empty?
51
- prop = (0..10).collect{|i| lengths[i].to_f/20000}
52
- assert((prop[-1] >= 0.45) && (prop[-1] <= 0.55))
53
- assert((prop[-2] >= 0.2) && (prop[-2] <= 0.3))
54
- assert((prop[-3] >= 0.1) && (prop[-3] <= 0.15))
55
- end
56
-
57
- def test_it_can_be_used_on_small_dfas
58
- dfa = RandomDFA.new(16).execute
59
- training, test = RandomSample.execute(dfa)
60
-
61
- assert test.size > 0
62
- assert training.size > 0
63
-
64
- # check training sample
65
- assert training.positive_count > 0
66
- assert training.negative_count > 0
67
- assert dfa.correctly_classify?(training)
68
-
69
- # check test sample
70
- assert test.positive_count > 0
71
- assert test.negative_count > 0
72
- assert dfa.correctly_classify?(test)
73
- end
74
-
75
-
76
- end # class RandomDFATest
77
- end # module Abbadingo
78
- end # module Stamina
@@ -1,516 +0,0 @@
1
- require 'test/unit'
2
- require 'stamina'
3
- module Stamina
4
-
5
- # Tests ADL parser
6
- class ADLTest < Test::Unit::TestCase
7
-
8
- # Tests ADL#parse on a valid dfa
9
- def test_can_parse_valid_empty_dfa
10
- fa = ADL::parse_automaton <<-AUTOMATON
11
- 1 0
12
- 0 true false
13
- AUTOMATON
14
- assert_equal(1, fa.state_count)
15
- assert_equal(0, fa.edge_count)
16
- assert_equal(true, fa.states[0].initial?)
17
- assert_equal(false, fa.states[0].accepting?)
18
- assert_equal(true, fa.deterministic?)
19
- assert_equal(false, fa.accepts?('+'))
20
- assert_equal(false, fa.accepts?('+ a'))
21
- end
22
-
23
- # Tests ADL#parse on a valid dfa
24
- def test_can_parse_valid_small_dfa
25
- fa = ADL::parse_automaton <<-AUTOMATON
26
- 3 4
27
- 0 true false
28
- 1 false false
29
- 2 false true
30
- 0 1 a
31
- 1 2 b
32
- 2 2 a
33
- 2 1 b
34
- AUTOMATON
35
- assert_equal(3, fa.state_count)
36
- assert_equal(4, fa.edge_count)
37
- fa.each_state {|s| assert_equal(s.index==0, s.initial?)}
38
- fa.each_state {|s| assert_equal(s.index==2, s.accepting?)}
39
- assert_equal(false, fa.accepts?('+'))
40
- assert_equal(false, fa.accepts?('+ a'))
41
- assert_equal(true, fa.accepts?('+ a b'))
42
- assert_equal(true, fa.accepts?('+ a b a'))
43
- assert_equal(false, fa.accepts?('+ a b a b'))
44
- assert_equal(true, fa.accepts?('+ a b a a a'))
45
- assert_equal(true, fa.accepts?('+ a b a a a b b a'))
46
- assert_equal(true, fa.accepts?('+ a b a a a b b a a a'))
47
- assert_equal(true, fa.accepts?('+ a b a a a b b a a a b b a'))
48
- end
49
-
50
- # Tests that ADL#parse detects a missing state
51
- def test_detect_missing_header
52
- assert_raise(ADL::ParseError) do
53
- ADL::parse_automaton <<-AUTOMATON
54
- 0 true false
55
- 1 false false
56
- 0 1 a
57
- 1 2 b
58
- 2 2 a
59
- 2 1 b
60
- AUTOMATON
61
- end
62
- assert_raise(ADL::ParseError) do
63
- ADL::parse_automaton <<-AUTOMATON
64
- # 3 4
65
- 0 true false
66
- 1 false false
67
- 0 1 a
68
- 1 2 b
69
- 2 2 a
70
- 2 1 b
71
- AUTOMATON
72
- end
73
- end
74
-
75
- # Tests that ADL#parse detects a missing state
76
- def test_detect_missing_state
77
- assert_raise(ADL::ParseError) do
78
- ADL::parse_automaton <<-AUTOMATON
79
- 3 4
80
- 0 true false
81
- 1 false false
82
- AUTOMATON
83
- end
84
- assert_raise(ADL::ParseError) do
85
- ADL::parse_automaton <<-AUTOMATON
86
- 3 4
87
- 0 true false
88
- 1 false false
89
- 0 1 a
90
- 1 2 b
91
- 2 2 a
92
- 2 1 b
93
- AUTOMATON
94
- end
95
- assert_raise(ADL::ParseError) do
96
- ADL::parse_automaton <<-AUTOMATON
97
- 3 4
98
- 0 true false
99
- 1 false false
100
- # 2 false true
101
- 0 1 a
102
- 1 2 b
103
- 2 2 a
104
- 2 1 b
105
- AUTOMATON
106
- end
107
- end
108
-
109
- # Tests that ADL#parse detects a missing edge
110
- def test_detect_missing_edge
111
- assert_raise(ADL::ParseError) do
112
- ADL::parse_automaton <<-AUTOMATON
113
- 3 4
114
- 0 true false
115
- 1 false false
116
- 2 false true
117
- 0 1 a
118
- 2 2 a
119
- 2 1 b
120
- AUTOMATON
121
- end
122
- assert_raise(ADL::ParseError) do
123
- ADL::parse_automaton <<-AUTOMATON
124
- 3 4
125
- 0 true false
126
- 1 false false
127
- 2 false true
128
- 0 1 a
129
- 1 2 b
130
- 2 2 a
131
- # 2 1 b
132
- AUTOMATON
133
- end
134
- end
135
-
136
- # Tests that ADL#parse detects a missing edge
137
- def test_detect_trailing_data
138
- assert_raise(ADL::ParseError) do
139
- fa = ADL::parse_automaton <<-AUTOMATON
140
- 1 0
141
- 0 true false
142
- trailing here
143
- AUTOMATON
144
- end
145
- end
146
-
147
- # Tests that ADL#parse detects a missing edge
148
- def test_allows_comments_and_white_lines
149
- fa = nil
150
- assert_nothing_raised(ADL::ParseError) do
151
- fa = ADL::parse_automaton <<-AUTOMATON
152
-
153
- # a header is always allowed,
154
- # with empty lines as well
155
- #
156
- 3 4
157
-
158
- # state definitions may be introduced...
159
- 0 true false
160
- 1 false false
161
- # and perturbated
162
- 2 false true
163
- 0 1 a
164
-
165
- # edge introduction may be misplaced
166
- 1 2 b
167
- 2 2 a
168
-
169
- 2 1 b
170
-
171
- # and end of file may contain documentation as well
172
- # as empty lines:
173
-
174
- AUTOMATON
175
- end
176
- assert_equal(3, fa.state_count)
177
- assert_equal(4, fa.edge_count)
178
- fa.each_state {|s| assert_equal(s.index==0, s.initial?)}
179
- fa.each_state {|s| assert_equal(s.index==2, s.accepting?)}
180
- assert_equal(false, fa.accepts?('+'))
181
- assert_equal(false, fa.accepts?('+ a'))
182
- assert_equal(true, fa.accepts?('+ a b'))
183
- assert_equal(true, fa.accepts?('+ a b a'))
184
- assert_equal(false, fa.accepts?('+ a b a b'))
185
- assert_equal(true, fa.accepts?('+ a b a a a'))
186
- assert_equal(true, fa.accepts?('+ a b a a a b b a'))
187
- assert_equal(true, fa.accepts?('+ a b a a a b b a a a'))
188
- assert_equal(true, fa.accepts?('+ a b a a a b b a a a b b a'))
189
- end
190
-
191
- # Tests ADL::parse on the documentation example
192
- def test_valid_adl_automaton_example
193
- fa = nil
194
- assert_nothing_raised(ADL::ParseError) do
195
- here = File.dirname(__FILE__)
196
- automaton_adl = File.join(here, '..', '..', 'example', 'adl', 'automaton.adl')
197
- fa = ADL::parse_automaton_file(automaton_adl)
198
- end # assert_nothing_raised
199
- assert_equal(5, fa.state_count)
200
- assert_equal(6, fa.edge_count)
201
- assert_equal(true, fa.parses?('? hello w o r l d'))
202
- assert_equal(false, fa.accepts?('? hello w o r l d'))
203
- assert_equal(true, fa.rejects?('? hello w o r l d'))
204
- assert_equal(true, fa.accepts?('? hello'))
205
- assert_equal(false, fa.accepts?('? hello w'))
206
- assert_equal(true, fa.accepts?('? hello w o'))
207
- assert_equal(false, fa.accepts?('? hello w o r'))
208
- assert_equal(false, fa.accepts?('? hello w o r l'))
209
- end
210
-
211
- # Tests ADL::parse on the documentation succint example
212
- def test_valid_adl_automaton_succint_example
213
- fa = nil
214
- assert_nothing_raised do
215
- fa = ADL::parse_automaton <<-AUTOMATON
216
- # Some header comments: tool which has generated this automaton,
217
- # maybe a date or other tool options ...
218
- # here: 'this automaton accepts the a(ba)* regular language'
219
- 2 2
220
- 0 true false
221
- 1 false true
222
- 0 1 a
223
- 1 0 b
224
- AUTOMATON
225
- end
226
- assert_equal(2, fa.state_count)
227
- assert_equal(2, fa.edge_count)
228
- assert_equal(true, fa.accepts?('? a'))
229
- assert_equal(true, fa.accepts?('? a b a'))
230
- assert_equal(true, fa.accepts?('? a b a b a'))
231
- assert_equal(false, fa.accepts?('?'))
232
- assert_equal(false, fa.accepts?('? a b'))
233
- assert_equal(false, fa.accepts?('? a b a b'))
234
- end
235
-
236
- # Checks that an initial state may arruve lately
237
- def test_parse_automaton_allows_late_initial_state
238
- fa = nil
239
- assert_nothing_raised do
240
- fa = ADL::parse_automaton <<-AUTOMATON
241
- # Some header comments: tool which has generated this automaton,
242
- # maybe a date or other tool options ...
243
- # here: 'this automaton accepts the a(ba)* regular language'
244
- 2 2
245
- 0 false false
246
- 1 true true
247
- 0 1 a
248
- 1 0 b
249
- AUTOMATON
250
- end
251
- end
252
-
253
- # Tests parse_automaton on an automated randomly generated using jail
254
- def test_parse_automaton_on_jail_randdfa
255
- fa = nil
256
- assert_nothing_raised do
257
- fa = ADL::parse_automaton_file(File.join(File.dirname(__FILE__),'randdfa.adl'))
258
- end
259
- end
260
-
261
- # Tests an important security issue about parse_automaton
262
- def test_parse_automaton_does_not_executes_ruby_code
263
- begin
264
- assert_raise ADL::ParseError do
265
- ADL::parse_automaton <<-AUTOMATON
266
- Kernel.exit(-1)
267
- AUTOMATON
268
- end
269
- rescue SystemExit
270
- assert false, 'SECURITY issue: ADL::parse_automaton executes ruby code'
271
- end
272
- begin
273
- assert_raise ADL::ParseError do
274
- ADL::parse_automaton_file(File.dirname(__FILE__)+'/exit.rb')
275
- end
276
- rescue SystemExit
277
- assert false, 'SECURITY issue: ADL::parse_automaton executes ruby code'
278
- end
279
- end
280
-
281
- # Tests ADL::parse_string
282
- def test_parse_string
283
- s = ADL::parse_string('?')
284
- assert_equal(true, InputString===s)
285
- assert_equal(false, s.positive?)
286
- assert_equal(false, s.negative?)
287
- assert_equal(true, s.unlabeled?)
288
- assert_equal(nil, s.label)
289
- assert_equal(true, s.empty?)
290
- assert_equal([], s.symbols)
291
-
292
- s = ADL::parse_string('+')
293
- assert_equal(true, InputString===s)
294
- assert_equal(true, s.positive?)
295
- assert_equal(true, s.label)
296
- assert_equal(true, s.empty?)
297
- assert_equal([], s.symbols)
298
-
299
- s = ADL::parse_string('-')
300
- assert_equal(true, InputString===s)
301
- assert_equal(false, s.positive?)
302
- assert_equal(false, s.label)
303
- assert_equal(true, s.empty?)
304
- assert_equal([], s.symbols)
305
-
306
- s = ADL::parse_string('? a')
307
- assert_equal(['a'], s.symbols)
308
- assert_equal(false, s.positive?)
309
- assert_equal(false, s.negative?)
310
- assert_equal(true, s.unlabeled?)
311
- assert_equal(nil, s.label)
312
- assert_equal(['a'], s.symbols)
313
-
314
- s = ADL::parse_string('+ a')
315
- assert_equal(['a'], s.symbols)
316
- assert_equal(true, s.positive?)
317
-
318
- s = ADL::parse_string('- a')
319
- assert_equal(['a'], s.symbols)
320
- assert_equal(false, s.positive?)
321
-
322
- s = ADL::parse_string('+ a b a b ')
323
- assert_equal(['a','b','a','b'], s.symbols)
324
- assert_equal(true, s.positive?)
325
-
326
- s = ADL::parse_string('- a b a c')
327
- assert_equal(['a','b','a','c'], s.symbols)
328
- assert_equal(false, s.positive?)
329
- end
330
-
331
- # Tests ADL::parse_sample
332
- def test_parse_sample
333
- sample = ADL::parse_sample <<-SAMPLE
334
- + a b a b a b
335
- # this is a comment, next is an empty line
336
- +
337
- + a b
338
- - a a
339
- ? a b
340
- # trailing comment allowed
341
- SAMPLE
342
- assert sample==Sample['+ a b a b a b', '+ a b', '- a a', '+', '? a b']
343
- end
344
-
345
- # Tests that ADL::parse_sample accepts the empty sample
346
- def test_parse_sample_accepts_empty_sample
347
- samples = [
348
- ADL::parse_sample(""),
349
- ADL::parse_sample("#"),
350
- ADL::parse_sample(<<-SAMPLE
351
- SAMPLE
352
- ),
353
- ADL::parse_sample(<<-SAMPLE
354
-
355
- # this is a comment, between two empty lines
356
-
357
- SAMPLE
358
- )
359
- ]
360
- samples.each do |sample|
361
- assert sample==Sample.new
362
- end
363
- end
364
-
365
- # Tests that ADL::parse_sample accepts empty strings
366
- def test_parse_sample_accepts_empty_strings
367
- assert Sample['+'] == ADL::parse_sample('+')
368
- assert Sample['-'] == ADL::parse_sample('-')
369
- assert Sample['+'] == ADL::parse_sample(<<-SAMPLE
370
- +
371
- SAMPLE
372
- )
373
- assert Sample['-'] == ADL::parse_sample(<<-SAMPLE
374
- -
375
- SAMPLE
376
- )
377
- end
378
-
379
- # Tests validity of sample.adl file
380
- def test_valid_adl_sample_example
381
- here = File.dirname(__FILE__)
382
- sample_adl = File.join(here, '..', '..', 'example', 'adl', 'sample.adl')
383
- sample = ADL::parse_sample_file(sample_adl)
384
- expected = Sample.new
385
- expected << InputString.new(['a', 'b', 'a', 'b'], true)
386
- expected << InputString.new(['a', 'a'], false)
387
- expected << InputString.new(['a', 'b'], nil)
388
- expected << InputString.new([], true)
389
- expected << InputString.new(['hello', 'world'], true)
390
- expected << InputString.new(['h','e','l','l','o','w','o','r','l','d'], true)
391
- expected << InputString.new(['helloworld'], true)
392
- expected << InputString.new(['a','+','b','-','a','-','b','+a'], true)
393
- expected << InputString.new(['#','a','#','b','a','b','#','and','all','these','words','are','symbols', 'too', '!!'],true)
394
- expected.each do |s|
395
- assert sample.include?(s), "|#{s}| from expected is included in sample"
396
- end
397
- sample.each do |s|
398
- assert expected.include?(s), "|#{s}| from sample is included in expected"
399
- end
400
- assert expected == sample
401
- end
402
-
403
- # Tests validity of sample.adl file
404
- def test_valid_adl_sample_succint_example
405
- sample = ADL::parse_sample <<-SAMPLE
406
- # Some header comments: tool which has generated this sample,
407
- # maybe a date or other tool options ...
408
- # here: 'this sample is caracteristic for the a(ba)* regular language'
409
- -
410
- + a
411
- - a b
412
- + a b a
413
- SAMPLE
414
- expected = Sample.new
415
- expected << InputString.new([], false)
416
- expected << InputString.new(['a'], true)
417
- expected << InputString.new(['a','b'], false)
418
- expected << InputString.new(['a','b','a'], true)
419
- assert expected==sample
420
- end
421
-
422
- # Tests an important security issue about parse_automaton
423
- def test_parse_sample_does_not_executes_ruby_code
424
- begin
425
- ADL::parse_sample <<-AUTOMATON
426
- + Kernel.exit(-1)
427
- AUTOMATON
428
- rescue SystemExit
429
- assert false, 'SECURITY issue: ADL::parse_automaton executes ruby code'
430
- end
431
- begin
432
- ADL::parse_sample_file(File.dirname(__FILE__)+'/exit.rb')
433
- rescue SystemExit
434
- assert false, 'SECURITY issue: ADL::parse_automaton executes ruby code'
435
- end
436
- end
437
-
438
- # tests that state IDs are loaded and can be used.
439
- def test_state_names
440
- fa = ADL::parse_automaton <<-AUTOMATON
441
- 3 4
442
- A true false
443
- B false false
444
- C false true
445
- A B a
446
- B C b
447
- C C a
448
- C B b
449
- AUTOMATON
450
-
451
- ['A','B','C'].each do |statename|
452
- assert_equal statename,fa.get_state(statename)[:name]
453
- end
454
-
455
- assert_equal true,fa.get_state('A').initial?
456
- assert_equal false,fa.get_state('B').initial?
457
- assert_equal false,fa.get_state('C').initial?
458
-
459
- assert_equal false,fa.get_state('A').accepting?
460
- assert_equal false,fa.get_state('B').accepting?
461
- assert_equal true,fa.get_state('C').accepting?
462
- end
463
-
464
- def test_parsing_recognizes_failures
465
- assert_raise Stamina::ADL::ParseError do
466
- fa = ADL::parse_sample <<-EOF
467
- 3 4
468
- A true false
469
- B false false
470
- C false true
471
- A B a
472
- B C b
473
- C C a
474
- C B b
475
- EOF
476
- end
477
- assert_raise Stamina::ADL::ParseError do
478
- sample = ADL::parse_automaton <<-EOF
479
- + a b a b a b
480
- # this is a comment, next is an empty line
481
- +
482
- + a b
483
- - a a
484
- a b
485
- # trailing comment allowed
486
- EOF
487
- end
488
- end
489
-
490
- def test_allows_error_states
491
- dfa = ADL::parse_automaton <<-EOF
492
- 5 0
493
- 0 true true true
494
- 1 false false true
495
- 2 false false false
496
- 3 false true false
497
- 4 false true
498
- EOF
499
- assert dfa.ith_state(0).accepting? && dfa.ith_state(0).error?
500
- assert !dfa.ith_state(1).accepting? && dfa.ith_state(1).error?
501
- assert !dfa.ith_state(2).accepting? && !dfa.ith_state(2).error?
502
- assert dfa.ith_state(3).accepting? && !dfa.ith_state(3).error?
503
- assert !dfa.ith_state(4).error?
504
- end
505
-
506
- def test_flushes_error_states
507
- dfa = ADL::parse_automaton <<-EOF
508
- 2 0
509
- 0 true false
510
- 1 false false true
511
- EOF
512
- assert_equal "1 false false true", dfa.to_adl.split("\n")[2].strip
513
- end
514
-
515
- end # class ADLTest
516
- end # module Stamina