mrubyc-test 0.1.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.
@@ -0,0 +1,54 @@
1
+ class Object
2
+ def to_ss
3
+ if self.class == NilClass
4
+ 'nil [NilClass]'
5
+ elsif self == ''
6
+ '[NULL String]'
7
+ else
8
+ self.to_s + ' [' + self.class_name + ']'
9
+ end
10
+ end
11
+ def class_name
12
+ case self.class
13
+ when String
14
+ 'String'
15
+ when Array
16
+ 'Array'
17
+ when FalseClass
18
+ 'FalseClass'
19
+ when Fixnum
20
+ 'Fixnum'
21
+ when Float
22
+ 'Float'
23
+ when Hash
24
+ 'Hash'
25
+ when Math
26
+ 'Math'
27
+ when Mutex
28
+ 'Mutex'
29
+ when Numeric
30
+ 'Numeric'
31
+ when Object
32
+ case self
33
+ when false
34
+ 'FalseClass'
35
+ when true
36
+ 'TrueClass'
37
+ else
38
+ 'Object'
39
+ end
40
+ when Proc
41
+ 'Proc'
42
+ when Range
43
+ 'Range'
44
+ when String
45
+ 'String'
46
+ when Symbol
47
+ 'Symbol'
48
+ when VM
49
+ 'VM'
50
+ else
51
+ '[User Defined Class]'
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mrubyc_test_case/mrubyc_test_case"
4
+ require "mrubyc/test/version"
5
+ require "mrubyc/test/config"
6
+ require "mrubyc/test/init"
7
+ require "mrubyc/test/generator/attribute"
8
+ require "mrubyc/test/generator/test_case"
9
+ require "mrubyc/test/generator/script"
10
+ require "mrubyc/test/generator/double"
11
+ require "thor"
12
+
13
+ module Mrubyc::Test
14
+ class Error < StandardError; end
15
+
16
+ class Tool < Thor
17
+ desc 'init', 'Initialize requirements for unit test of mruby/c. Some directories and files will be created. Note that existing objects may be overridden'
18
+ def init
19
+ Mrubyc::Test::Init.run
20
+ end
21
+
22
+ desc 'prepare', 'Create a ruby script that has all the requirements of your test'
23
+ def prepare
24
+ config = Mrubyc::Test::Config.read
25
+ model_files = Dir.glob(File.join(Dir.pwd, config['mruby_lib_dir'], 'models', '*.rb'))
26
+ test_path = File.join(Dir.pwd, config['test_dir'], '*.rb')
27
+ test_files = Dir.glob(test_path)
28
+ if test_files.size == 0
29
+ puts 'Test not found'
30
+ puts 'search path: ' + test_path
31
+ exit(1)
32
+ end
33
+
34
+ # gather attributes from your implementations and tests
35
+ attributes = Mrubyc::Test::Generator::Attribute.run(model_files: model_files, test_files: test_files)
36
+
37
+ # convert attributes into tast_cases
38
+ test_cases = Mrubyc::Test::Generator::TestCase.run(attributes)
39
+
40
+ # generate a ruby script that will be compiled by mrbc and executed in mruby/c VM
41
+ Mrubyc::Test::Generator::Script.run(model_files: model_files, test_files: test_files, test_cases: test_cases)
42
+ end
43
+
44
+ desc 'make', 'compile test script into executable && run it'
45
+ def make
46
+ config = Mrubyc::Test::Config.read
47
+ tmp_dir = File.join(Dir.pwd, config['test_tmp_dir'])
48
+ puts "cd #{tmp_dir}"
49
+ puts
50
+ exit_code = 0
51
+ pwd = Dir.pwd
52
+ FileUtils.mv "#{pwd}/#{config['mrubyc_src_dir']}/hal", "#{pwd}/#{config['mrubyc_src_dir']}/~hal"
53
+ begin
54
+ FileUtils.ln_s "#{pwd}/#{config['test_tmp_dir']}/hal", "#{pwd}/#{config['mrubyc_src_dir']}/hal"
55
+ Dir.chdir(tmp_dir) do
56
+ ['~/.rbenv/versions/mruby-1.4.1/bin/mrbc -E -B test test.rb',
57
+ "cc -I #{pwd}/#{config['mrubyc_src_dir']} -DMRBC_DEBUG -o test main.c #{pwd}/#{config['mrubyc_src_dir']}/*.c #{pwd}/#{config['mrubyc_src_dir']}/hal/*.c",
58
+ './test'].each do |cmd|
59
+ puts cmd
60
+ puts
61
+ exit_code = system(cmd) ? 0 : 1
62
+ end
63
+ puts
64
+ puts "cd -"
65
+ puts
66
+ end
67
+ ensure
68
+ FileUtils.rm "#{pwd}/#{config['mrubyc_src_dir']}/hal"
69
+ FileUtils.mv "#{pwd}/#{config['mrubyc_src_dir']}/~hal", "#{pwd}/#{config['mrubyc_src_dir']}/hal"
70
+ end
71
+ exit(exit_code)
72
+ end
73
+
74
+ desc 'test', 'shortcut for `prepare` && `make`'
75
+ def test
76
+ prepare
77
+ make
78
+ end
79
+ end
80
+ end
81
+
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+
6
+ module Mrubyc
7
+ module Test
8
+ class Config
9
+ class << self
10
+ def read(check: true)
11
+ FileUtils.touch('.mrubycconfig')
12
+ config = YAML.load_file('.mrubycconfig')
13
+ if check
14
+ if !config || config == [] || !config['test_dir']
15
+ raise 'Check if `.mrubycconfig` exists.'
16
+ end
17
+ end
18
+ config || {}
19
+ end
20
+
21
+ def write(config)
22
+ File.open('.mrubycconfig', 'r+') do |file|
23
+ file.write(config.to_yaml)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/string/inflections'
4
+
5
+ module Mrubyc
6
+ module Test
7
+ module Generator
8
+ class Attribute
9
+ class << self
10
+ def run(model_files: [], test_files:)
11
+ # get information from model files(application code)
12
+ model_files.each do |model_file|
13
+ load model_file
14
+ model_class = Module.const_get(File.basename(model_file, '.rb').camelize)
15
+ model_class.class_eval do
16
+ def method_missing(_method_name, *_args)
17
+ # do nothing
18
+ end
19
+ end
20
+ end
21
+ # get information from test files
22
+ method_locations = {}
23
+ description_locations = {}
24
+ double_method_locations = {}
25
+ test_files.each do |test_file|
26
+ load test_file
27
+ test_class = Module.const_get(File.basename(test_file, '.rb').camelize)
28
+ method_locations.merge!(test_class.class_variable_get(:@@method_locations))
29
+ description_locations.merge!(test_class.class_variable_get(:@@description_locations))
30
+ my_test = test_class.new
31
+ double_method_locations[test_class] = []
32
+ test_class.class_variable_get(:@@added_method_names)[test_class].each do |method_name, _v|
33
+ Mrubyc::Test::Generator::Double.init_double_method_locations
34
+ begin
35
+ my_test.send(method_name)
36
+ rescue NoMethodError => e
37
+ end
38
+ double_method_locations[test_class] << { method_name => Mrubyc::Test::Generator::Double.class_variable_get(:@@double_method_locations) }
39
+ end
40
+ end
41
+ { method_locations: method_locations,
42
+ description_locations: description_locations,
43
+ double_method_locations: double_method_locations }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mrubyc
4
+ module Test
5
+ module Generator
6
+ class Double
7
+ class << self
8
+ def init_double_method_locations
9
+ @@double_method_locations = []
10
+ end
11
+ end
12
+
13
+ def initialize(type, object, location)
14
+ @type = type
15
+ @klass = object.class
16
+ @location = location
17
+ end
18
+
19
+ def method_missing(method_name, *args)
20
+ @@double_method_locations << {
21
+ type: @type,
22
+ class: @klass,
23
+ method_name: method_name,
24
+ args: args.to_s,
25
+ block: (block_given? ? yield : nil),
26
+ label: @location.label,
27
+ path: @location.absolute_path || @location.path,
28
+ line: @location.lineno
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rufo'
4
+ require 'erb'
5
+
6
+ module Mrubyc
7
+ module Test
8
+ module Generator
9
+ class Script
10
+ class << self
11
+ def run(model_files: [], test_files:, test_cases:)
12
+ config = Mrubyc::Test::Config.read
13
+ erb = ERB.new(File.read(File.expand_path('../../../../templates/test.rb.erb', __FILE__)), nil, '-')
14
+ mrubyc_class_dir = File.expand_path('../../../../mrubyc-ext/', __FILE__)
15
+ File.write(File.join(config['test_tmp_dir'], 'test.rb'), Rufo.format(erb.result(binding)))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mrubyc
4
+ module Test
5
+ module Generator
6
+ class TestCase
7
+ class << self
8
+ def run(attributes)
9
+ test_cases = []
10
+ attributes[:method_locations].each do |klass, methods|
11
+ methods.each do |method|
12
+ if attributes[:description_locations].size > 0
13
+ found_desc = attributes[:description_locations][klass].find do |hash|
14
+ hash[:line] == method[:line] -1
15
+ end
16
+ end
17
+ description = found_desc ? found_desc[:text] : ''
18
+ information = {
19
+ test_class_name: klass.to_s,
20
+ method_name: method[:method_name],
21
+ path: method[:path],
22
+ line: method[:line],
23
+ description: description
24
+ }
25
+ stubs = []
26
+ mocks = []
27
+ attributes[:double_method_locations][klass].each do |hash|
28
+ if hash.keys[0] == method[:method_name]
29
+ hash[method[:method_name]].each do |double|
30
+ stub_or_mock = { class_name: double[:class].to_s,
31
+ instance_variables: nil, # TODO
32
+ method_name: double[:method_name].to_s,
33
+ args: double[:args],
34
+ return_value: double[:block],
35
+ line: double[:line]
36
+ }
37
+ if double[:type] == :stub
38
+ stubs << stub_or_mock
39
+ else
40
+ mocks << stub_or_mock
41
+ end
42
+ end
43
+ end
44
+ end
45
+ test_cases << {
46
+ information: information,
47
+ stubs: stubs,
48
+ mocks: mocks
49
+ }
50
+ end
51
+ end
52
+ test_cases
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+ require 'fileutils'
5
+
6
+ module Mrubyc
7
+ module Test
8
+ class Init
9
+ class << self
10
+ def run
11
+ puts 'Initializing...'
12
+ puts
13
+
14
+ puts ' touch .mrubycconfig'
15
+ config = Mrubyc::Test::Config.read(check: false)
16
+ config['test_dir'] = 'test'
17
+ config['test_tmp_dir'] = 'test/tmp'
18
+ config['mruby_lib_dir'] = 'mrblib'
19
+ puts ' add config to .mrubycconfig'
20
+ Mrubyc::Test::Config.write(config)
21
+
22
+ hal_dir = "#{config['test_tmp_dir']}/hal"
23
+ puts " mikdir -p #{hal_dir}"
24
+ FileUtils.mkdir_p(hal_dir)
25
+
26
+ Dir.chdir(hal_dir) do
27
+ puts " download from https://raw.githubusercontent.com/mrubyc/mrubyc/master/src/hal_posix/hal.h"
28
+ system 'wget https://raw.githubusercontent.com/mrubyc/mrubyc/master/src/hal_posix/hal.h'
29
+ puts " download from https://raw.githubusercontent.com/mrubyc/mrubyc/master/src/hal_posix/hal.c"
30
+ system 'wget https://raw.githubusercontent.com/mrubyc/mrubyc/master/src/hal_posix/hal.c'
31
+ end
32
+
33
+
34
+ puts " mikdir -p #{config['mruby_lib_dir']}/models"
35
+ FileUtils.mkdir_p('test/tmp')
36
+
37
+ puts ' cp test/sample_test.rb'
38
+ erb = ERB.new(File.read(File.expand_path('../../../templates/sample_test.rb.erb', __FILE__)), nil, '-')
39
+ File.write(File.join(config['test_dir'], 'sample_test.rb'), erb.result(binding))
40
+
41
+ puts ' cp test/tmp/main.c'
42
+ erb = ERB.new(File.read(File.expand_path('../../../templates/main.c.erb', __FILE__)), nil, '-')
43
+ File.write(File.join(config['test_tmp_dir'], 'main.c'), erb.result(binding))
44
+
45
+ puts
46
+ puts "\e[32mWelcome to mrubyc-test, the world\'s first TDD tool for mruby/c microcontroller development.\e[37m"
47
+ puts "\e[33m"
48
+ puts 'Caution:'
49
+ puts 'For the time being, mrubyc-test assumes you installed mruby-1.4.1 by rbenv. So you should have `~/.rbenv/versions/mruby-1.4.1/bin.mrbc`'
50
+ puts 'Sorry for the inconvenience. It will be fixed soon!'
51
+ puts "\e[37m"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ module Mrubyc
2
+ module Test
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mrubyc/test/generator/double'
4
+
5
+ class MrubycTestCase
6
+ class << self
7
+ @@description_locations = {}
8
+ def description(text)
9
+ location = caller_locations(1, 1)[0]
10
+ path = location.absolute_path || location.path
11
+ line = location.lineno
12
+ location = {
13
+ text: text,
14
+ path: File.expand_path(path),
15
+ line: line,
16
+ }
17
+ add_description_location(location)
18
+ end
19
+ alias :desc :description
20
+
21
+ @@added_method_names = {}
22
+ @@method_locations = {}
23
+ def method_added(name)
24
+ return false if %i(method_missing setup teardown).include?(name)
25
+ # puts "method '#{self}' '#{name}' '#{name.class}' was added"
26
+ added_method_names = (@@added_method_names[self] ||= {})
27
+ stringified_name = name.to_s
28
+ location = caller_locations(1, 1)[0]
29
+ path = location.absolute_path || location.path
30
+ line = location.lineno
31
+ location = {
32
+ method_name: stringified_name,
33
+ path: File.expand_path(path),
34
+ line: line,
35
+ }
36
+ add_method_location(location)
37
+ added_method_names[stringified_name] = true
38
+ end
39
+
40
+ def added_method_names
41
+ (@@added_method_names[self] ||= {}).keys
42
+ end
43
+
44
+ private
45
+
46
+ # for RSpec
47
+ def init_class_variables
48
+ @@description_locations = {}
49
+ @@method_locations = {}
50
+ @@added_method_names = {}
51
+ end
52
+
53
+ def method_locations
54
+ @@method_locations[self] ||= []
55
+ end
56
+
57
+ def add_method_location(location)
58
+ method_locations << location
59
+ end
60
+
61
+ def description_locations
62
+ @@description_locations[self] ||= []
63
+ end
64
+
65
+ def add_description_location(location)
66
+ description_locations << location
67
+ end
68
+
69
+ end
70
+
71
+ def method_missing(method_name, *args)
72
+ case method_name
73
+ when :stub, :mock
74
+ location = caller_locations(1, 1)[0]
75
+ Mrubyc::Test::Generator::Double.new(method_name, args[0], location)
76
+ end
77
+ end
78
+ end
79
+