test65 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fb249a06581fa2e69553600dc88ec52b620db6d5
4
+ data.tar.gz: cdbc6072308051d64c07c61e0c9d07ded8319b2e
5
+ SHA512:
6
+ metadata.gz: cca5d442da99eb33a2fcc40f40029e4981e03fddeb037cb7b1e8b5123235b2725e0bc40a4e9927e9bb394827535048b9e5ad7d93ad360e25f99cfba2517ddc59
7
+ data.tar.gz: fdb97d5bbe8f9c7671904ab4591749740e2860d544416a04e269d13a5caac869da6c3173997d7b756b2db21b6ec0ff2ccd8cfed7fd75a7834b164514e2c5fd01
@@ -0,0 +1,5 @@
1
+ *.out
2
+ *.o
3
+ *.lst
4
+ pkg
5
+ foo
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at peter.c.camilleri@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in test65.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 PeterCamilleri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,159 @@
1
+ # Test65
2
+
3
+ This is a simple program written to allow the testing of 65C02 code that
4
+ I am writing for the Commander X 16 neo-retro computer.
5
+
6
+ Note: This program has recently undergone a lot of upgrades and is now ready
7
+ to release as a Ruby gem.
8
+
9
+ ## Installation
10
+
11
+ To install, first install the cc65 compiler and ensure that it is available at
12
+ the command line. You can test the required components with:
13
+
14
+ ca65 --version
15
+ ld65 --version
16
+ sim65 --version
17
+ set CC65_HOME
18
+
19
+ Then to install the gem, use:
20
+
21
+ $ gem install test65
22
+
23
+ ## Usage
24
+
25
+ test65 - Run tests of 65c02 assembler code.
26
+
27
+ Usage: test65 {options} {files}
28
+
29
+ Options:
30
+ --debug, -d Show (really) detailed debug info. Not normally required.
31
+ --help, -h, -? Display this message and exit.
32
+ --list, -l Generate list files for each test.
33
+ --map, -m Generate map files for each test.
34
+ --keep, -k Keep object and output files. Do not clean up.
35
+ --path, -p Specify the path to the test files. (Only 1 allowed)
36
+ --quiet, -q Hide messages. Used to keep the test65 tests clean.
37
+ --verbose, -v Display lots of useful progress info.
38
+ --version Display the program version and exit.
39
+
40
+ Files: An optional list of test files.
41
+
42
+ Notes:
43
+ - By default, test files are located in a folder called "t65" in the current
44
+ folder or one of its parent folders.
45
+ - Wildcards are allowed for files but not the path.
46
+ - If no files are specified, then all files matching "t65*.a65" or "t65*.rb"
47
+ in the test folder are tested.
48
+ - If files are specified, only the specified file(s) are tested.
49
+
50
+ ## Test Files
51
+
52
+ The test65 utility finds test files in one of two ways:
53
+
54
+ 1. The test files can be listed explicitly on the command line.
55
+ 2. Test files, of the appropriate extension, located in the test folder, are
56
+ "batch" run.
57
+
58
+ The tests are located in a test folder. This can be:
59
+
60
+ 1. Explicitly named using the --path option. (See above)
61
+ 2. Located in the t65 folder, either off of the current folder, or one of
62
+ its parent folders.
63
+
64
+ Test files can be:
65
+
66
+ 1. Assembly files with a suffix of ".a65".
67
+ 2. Ruby script files with a suffix of ".rb".
68
+
69
+ Future versions may support alternate extension types for assembler (like
70
+ ".asm" for example) and tests written in the "C" language with extensions
71
+ of ".c65" and maybe ".c".
72
+
73
+ ## Test Scripts in Ruby
74
+
75
+ The test65 gem uses Ruby scripts to allow for cases not handled by the
76
+ conventional defaults. The basic form of these scripts is:
77
+
78
+ ```
79
+ # Minimum script to pass a test.
80
+
81
+ Test65.script do
82
+ ca65 "min_pass.a65"
83
+ ld65
84
+ sim65
85
+ end
86
+ ```
87
+
88
+ The order matters and is:
89
+
90
+ assembly and compiling then linking then simulation
91
+
92
+ If the order is wrong, there will be errors.
93
+
94
+ ### Assembly
95
+
96
+ Code is assembled using the _ca65_ statement. It is supported by the
97
+ _ca65\_inc\_paths_ method. They are:
98
+
99
+ ```
100
+ ca65_inc_paths <path>, <optional more paths>, <etc>, <etc>, <etc>
101
+ ca65 "source_file", "optional options"
102
+ ```
103
+
104
+ Where _ca65\_inc\_paths_ is used to tell the assembler where to find included
105
+ files and _ca65_ does the work of converting the source file to an
106
+ object file.
107
+
108
+ ### Linking
109
+
110
+ Code is linked using the _ld65_ statement. It is supported by the
111
+ _ld65\_lib\_paths_ and _ld65\_libraries_. Here they are:
112
+
113
+ ```
114
+ ld65_lib_paths "path to libraries", <etc>, <etc>, <etc>
115
+ ld65_libraries "library", <etc>, <etc>, <etc>
116
+ ld65 "optional options"
117
+ ```
118
+
119
+ Where _ld65\_lib\_paths_ tells the linker where to find library files and
120
+ _ld65\_libraries_ specifies those libraries. After any ld65 method, no further
121
+ ca65* methods are permitted. After _ld65_ no further ld65* methods are
122
+ permitted either.
123
+
124
+ ### Simulation
125
+
126
+ Finally, the simulation phase runs the actual tests. This is simply:
127
+
128
+ ```
129
+ sim65 "optional options"
130
+ ```
131
+
132
+ When this is done, no further test statements are permitted. However it is
133
+ possible to perform multiple tests in one script file. Simply code
134
+ multiple Test65.script { ... } blocks in the one Ruby script file. They
135
+ will be run one after another, in order.
136
+
137
+ ## Contributing
138
+ 1. Fork it
139
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
140
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
141
+ 4. Push to the branch (`git push origin my-new-feature`)
142
+ 5. Create new Pull Request
143
+
144
+ OR...
145
+
146
+ * Make a suggestion by raising an
147
+ [issue](https://github.com/PeterCamilleri/test65/issues)
148
+ . All ideas and comments are welcome.
149
+
150
+ ## License
151
+
152
+ The gem is available as open source under the terms of the
153
+ [MIT License](./LICENSE.txt).
154
+
155
+ ## Code of Conduct
156
+
157
+ Everyone interacting in the test65project’s codebases, issue trackers,
158
+ chat rooms and mailing lists is expected to follow the
159
+ [code of conduct](./CODE_OF_CONDUCT.md).
@@ -0,0 +1,87 @@
1
+ ; Macro definitions for testing 65c02 code using sim65.
2
+
3
+ .import exit:absolute ; Make sure we have this symbol defined.
4
+
5
+ ; Exit tests and return success!
6
+ .macro tests_pass
7
+ lda #0
8
+ jmp exit
9
+ .endmacro
10
+
11
+ ; Exit tests and return an error code :-(
12
+ .macro tests_fail err_code
13
+ .ifconst err_code
14
+ .if (err_code < 2) || (err_code > 255)
15
+ .fatal "Invalid error code. Allowed values 2..255"
16
+ .endif
17
+
18
+ lda #err_code
19
+ jmp exit
20
+ .else
21
+ .fatal "Error code must be a constant"
22
+ .endif
23
+ .endmacro
24
+
25
+ ; Exit tests and return an error code if the Z flag is cleared (ne)
26
+ .macro fail_ne err_code
27
+ .local no_error
28
+ beq no_error
29
+ tests_fail err_code
30
+ no_error:
31
+ .endmacro
32
+
33
+ ; Exit tests and return an error code if the Z flag is set (eq)
34
+ .macro fail_eq err_code
35
+ .local no_error
36
+ bne no_error
37
+ tests_fail err_code
38
+ no_error:
39
+ .endmacro
40
+
41
+ ; Exit tests and return an error code if the C flag is cleared (cc)
42
+ .macro fail_cc err_code
43
+ .local no_error
44
+ bcs no_error
45
+ tests_fail err_code
46
+ no_error:
47
+ .endmacro
48
+
49
+ ; Exit tests and return an error code if the C flag is set (cs)
50
+ .macro fail_cs err_code
51
+ .local no_error
52
+ bcc no_error
53
+ tests_fail err_code
54
+ no_error:
55
+ .endmacro
56
+
57
+ ; Exit tests and return an error code if the N flag is cleared (pl)
58
+ .macro fail_pl err_code
59
+ .local no_error
60
+ bmi no_error
61
+ tests_fail err_code
62
+ no_error:
63
+ .endmacro
64
+
65
+ ; Exit tests and return an error code if the N flag is set (mi)
66
+ .macro fail_mi err_code
67
+ .local no_error
68
+ bpl no_error
69
+ tests_fail err_code
70
+ no_error:
71
+ .endmacro
72
+
73
+ ; Exit tests and return an error code if the V flag is cleared (vc)
74
+ .macro fail_vc err_code
75
+ .local no_error
76
+ bvs no_error
77
+ tests_fail err_code
78
+ no_error:
79
+ .endmacro
80
+
81
+ ; Exit tests and return an error code if the V flag is set (vs)
82
+ .macro fail_vs err_code
83
+ .local no_error
84
+ bvc no_error
85
+ tests_fail err_code
86
+ no_error:
87
+ .endmacro
@@ -0,0 +1,37 @@
1
+ SYMBOLS {
2
+ __EXEHDR__: type = import;
3
+ __STACKSIZE__: type = weak, value = $0800; # 2k stack
4
+ }
5
+ MEMORY {
6
+ ZP: file = "", start = $0000, size = $0100;
7
+ HEADER: file = %O, start = $0000, size = $000C;
8
+ MAIN: file = %O, define = yes, start = $0200, size = $FDF0 - __STACKSIZE__;
9
+ }
10
+ SEGMENTS {
11
+ ZEROPAGE: load = ZP, type = zp;
12
+ EXEHDR: load = HEADER, type = ro;
13
+ STARTUP: load = MAIN, type = ro;
14
+ LOWCODE: load = MAIN, type = ro, optional = yes;
15
+ ONCE: load = MAIN, type = ro, optional = yes;
16
+ CODE: load = MAIN, type = ro;
17
+ RODATA: load = MAIN, type = ro;
18
+ PAGE_CODE: load = MAIN, type = ro, optional = yes, align = $100;
19
+ DATA: load = MAIN, type = rw;
20
+ PAGE_DATA: load = MAIN, type = rw, optional = yes, align = $100;
21
+ BSS: load = MAIN, type = bss, define = yes;
22
+ }
23
+ FEATURES {
24
+ CONDES: type = constructor,
25
+ label = __CONSTRUCTOR_TABLE__,
26
+ count = __CONSTRUCTOR_COUNT__,
27
+ segment = ONCE;
28
+ CONDES: type = destructor,
29
+ label = __DESTRUCTOR_TABLE__,
30
+ count = __DESTRUCTOR_COUNT__,
31
+ segment = RODATA;
32
+ CONDES: type = interruptor,
33
+ label = __INTERRUPTOR_TABLE__,
34
+ count = __INTERRUPTOR_COUNT__,
35
+ segment = RODATA,
36
+ import = __CALLIRQ__;
37
+ }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ #The test65 command line script.
3
+
4
+ require_relative '../lib/test65'
5
+
6
+ Test65.process
@@ -0,0 +1,24 @@
1
+ test65 - Run tests of 65c02 assembler code.
2
+
3
+ Usage: test65 {options} {files}
4
+
5
+ Options:
6
+ --debug, -d Show (really) detailed debug info. Not normally required.
7
+ --help, -h, -? Display this message and exit.
8
+ --list, -l Generate list files for each test.
9
+ --map, -m Generate map files for each test.
10
+ --keep, -k Keep object and output files. Do not clean up.
11
+ --path, -p Specify the path to the test files. (Only 1 allowed)
12
+ --quiet, -q Hide messages. Used to keep the test65 tests clean.
13
+ --verbose, -v Display lots of useful progress info.
14
+ --version Display the program version and exit.
15
+
16
+ Files: An optional list of test files.
17
+
18
+ Notes:
19
+ - By default, test files are located in a folder called "t65" in the current
20
+ folder or one of its parent folders.
21
+ - Wildcards are allowed for files but not the path.
22
+ - If no files are specified, then all files matching "t65*.a65" or "t65*.rb"
23
+ in the test folder are tested.
24
+ - If files are specified, only the specified file(s) are tested.
@@ -0,0 +1,50 @@
1
+ # test65
2
+
3
+ require 'english'
4
+ require 'getoptlong'
5
+ require 'pathname'
6
+ require 'rbconfig'
7
+ require 'full_dup'
8
+
9
+ require_relative 'test65/perform_test'
10
+ require_relative 'test65/process_files'
11
+ require_relative 'test65/process_args'
12
+ require_relative 'test65/process_path'
13
+ require_relative 'test65/build_file_list'
14
+ require_relative 'test65/std_path'
15
+ require_relative 'test65/host'
16
+ require_relative 'test65/version'
17
+
18
+ module Test65
19
+
20
+ #Figure out where the gem root folder is located
21
+ lib_path = File.dirname(File.absolute_path(__FILE__))
22
+ @gem_root = Pathname.new(lib_path).parent.to_s
23
+ @asminc = @gem_root + "/asminc" # TODO remove this variable.
24
+
25
+ # Figure out where the compiler is.
26
+ temp = ENV["CC65_HOME"]
27
+ fail "The CC65_HOME variable is not set." unless temp
28
+ @cc65_home = temp.standardize_path
29
+
30
+ # The code entry point. Run some 65c02 tests.
31
+ # Returns
32
+ # 0 for success
33
+ # Other for failure
34
+ def self.process
35
+ process_args
36
+ process_path
37
+ build_file_list
38
+ process_file_list
39
+
40
+ rescue => err
41
+ puts "Error: #{err.to_s}"
42
+ puts err.backtrace if @options[:debug]
43
+ exit(1)
44
+
45
+ ensure
46
+ # Always remove this file if it exists.
47
+ File.delete("_kwhyit") if File.exists?("_kwhyit")
48
+ end
49
+
50
+ end
@@ -0,0 +1,37 @@
1
+ # Build the list of test and library files to be processed.
2
+
3
+ module Test65
4
+ # Find the files to be tested.
5
+ def self.build_file_list
6
+ if @arg_files.empty?
7
+ scan_files
8
+ else
9
+ check_files
10
+ end
11
+
12
+ puts "Processing #{@test_files.length} test file(s)" if @options[:verbose]
13
+ end
14
+
15
+ # Scan the path for files to be processed.
16
+ def self.scan_files
17
+ @test_files = Dir.glob(@options[:path] + "/t65*.a65") +
18
+ Dir.glob(@options[:path] + "/t65*.rb")
19
+ fail "Cannot locate any test files" if @test_files.empty?
20
+ end
21
+
22
+ # Check the list of files to be processed.
23
+ def self.check_files
24
+ @test_files = @arg_files.map do |file|
25
+ std_file = file.standardize_path
26
+
27
+ if !(found = Dir.glob(std_file)).empty?
28
+ found.map {|subfile| File.absolute_path(file) }
29
+ elsif !(found = Dir.glob(@options[:path] + "/" + std_file)).empty?
30
+ found
31
+ else
32
+ fail "Cannot locate the file #{file}"
33
+ end
34
+ end.flatten
35
+ end
36
+
37
+ end
@@ -0,0 +1,35 @@
1
+ # An enclosure for the ca65 assembler.
2
+ class TestScript
3
+
4
+ # Setup ca65
5
+ def ca65_initialize
6
+ @options[:target] = "sim65c02"
7
+ @options[:ca65_paths] = ["#{@options[:gem_root]}/asminc"]
8
+ @options[:objs] = []
9
+ end
10
+
11
+ # Add some include paths for the assembler.
12
+ def ca65_inc_paths(*more_paths)
13
+ fail "Sequence error: ca65_inc_paths" unless @phase == :create
14
+ append_option(:inc_paths, more_paths)
15
+ end
16
+
17
+ # Assemble some files.
18
+ def ca65(file, options="")
19
+ fail "Sequence error: ca65" unless @phase == :create
20
+ source = File.absolute_path(@options[:path] + "/" + file)
21
+ target = "--target #{@options[:target]} "
22
+ paths = build_args("-I", @options[:ca65_paths])
23
+
24
+ # Convert source assemble files into object files.
25
+ object = change_type(source, ".o")
26
+ list = @options[:list] ? "-l " + change_type(source, ".lst") : ""
27
+ command = "ca65 #{target}#{paths}#{list}#{options} -o #{object} #{source} #{@quiet}\n"
28
+ puts command if @options[:debug]
29
+ system(command)
30
+ fail "Error assembling #{source.localize_path}" unless $?.exitstatus == 0
31
+
32
+ @options[:objs] << object
33
+ end
34
+
35
+ end
@@ -0,0 +1,46 @@
1
+ # An enclosure for the ld65 linker.
2
+
3
+ class TestScript
4
+
5
+ # Setup ld65
6
+ def ld65_initialize
7
+ @options[:lib_paths] = []
8
+ @options[:libraries] = ["sim65c02.lib"]
9
+ @options[:ld65_options] = []
10
+ @options[:config] = "#{@options[:gem_root]}/cfg/test65.cfg"
11
+ end
12
+
13
+ # Add some library paths for the linker.
14
+ def ld65_lib_paths(*more_paths)
15
+ fail "Sequence error: ld65_lib_paths" unless [:create, :link].include?(@phase)
16
+ append_option(:lib_paths, more_paths)
17
+ @phase = :link
18
+ end
19
+
20
+ # Add some library paths for the linker.
21
+ def ld65_libraries(*more_libs)
22
+ fail "Sequence error: ld65_libraries" unless [:create, :link].include?(@phase)
23
+ append_option(:libraries, more_libs)
24
+ @phase = :link
25
+ end
26
+
27
+ def ld65(options="")
28
+ fail "Sequence error: ld65" unless [:create, :link].include?(@phase)
29
+ @phase = :simulate
30
+
31
+ @output = change_type(@options[:objs][0], ".out")
32
+ @map_file = change_type(@options[:objs][0], ".map")
33
+ lib_paths = build_args("--lib-path", @options[:lib_paths])
34
+ objs = build_args(@options[:objs])
35
+ libs = build_args("--lib", @options[:libraries])
36
+ map = @options[:map] ? "-m #{@map_file}" : ""
37
+ cfg = "-C " + @options[:config] + " "
38
+
39
+ # Build the command and run it.
40
+ command = "ld65 #{lib_paths}#{libs}#{cfg}#{options} #{objs}#{map} -o #{@output} #{@quiet}\n"
41
+ puts command if @options[:debug]
42
+ system(command)
43
+ fail "Error linking #{@output.localize_path}." unless $?.exitstatus == 0
44
+ end
45
+
46
+ end
@@ -0,0 +1,23 @@
1
+ # An enclosure for the sim65 simulator.
2
+
3
+ class TestScript
4
+
5
+ # Setup sim65
6
+ def sim65_initialize
7
+ @options[:sim65_options] = []
8
+ end
9
+
10
+ # Run the simulator to get the actual test results.
11
+ def sim65(options="")
12
+ fail "Sequence error: sim65" unless @phase == :simulate
13
+ @phase = :done
14
+
15
+ # Build the command and run it.
16
+ command = "sim65 #{options} #{@output} #{@quiet}\n"
17
+ puts command if @options[:debug]
18
+ system(command)
19
+ status = $?.exitstatus
20
+ fail "Test #{@output.localize_path} failed with error code: #{status}" unless status == 0
21
+ end
22
+
23
+ end
@@ -0,0 +1,26 @@
1
+ # Utility methods
2
+
3
+ class TestScript
4
+
5
+ # Create a file name with a new extension.
6
+ def change_type(file, new_ext)
7
+ file.gsub(/\...?.?\z/, new_ext)
8
+ end
9
+
10
+ # Construct a series of arguments.
11
+ def build_args(prefix = nil, args)
12
+ pre = prefix ? prefix + " " : ""
13
+ args.inject("") {|str, arg| str << pre + arg + " "}
14
+ end
15
+
16
+ # Append to an option.
17
+ def append_option(key, *value)
18
+ @options[key] = ((@options[key] || []) + [value]).flatten
19
+ end
20
+
21
+ # Adjust a list of files to include the path to the test file.
22
+ def adjust(files)
23
+ files.map { |file| @options[:path] + "/" + file }
24
+ end
25
+
26
+ end
@@ -0,0 +1,13 @@
1
+ # Is this program running on a Windows host?
2
+
3
+ class Object
4
+
5
+ private
6
+
7
+ # Are we running under Windows?
8
+ def windows?
9
+ # Is this a Windows based system
10
+ @win ||= RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|bccwin|wince|emc/
11
+ end
12
+
13
+ end
@@ -0,0 +1,45 @@
1
+ # Run a test script for the test65 program.
2
+
3
+ require_relative 'enclosures/utils'
4
+ require_relative 'enclosures/ca65'
5
+ require_relative 'enclosures/ld65'
6
+ require_relative 'enclosures/sim65'
7
+
8
+ class TestScript
9
+
10
+ # Create a test script object and set up its default options.
11
+ def initialize(options={})
12
+ @options = options.full_dup
13
+ @phase = :create
14
+
15
+ ca65_initialize
16
+ ld65_initialize
17
+ sim65_initialize
18
+
19
+ @quiet = @options[:quiet].to_s
20
+ end
21
+
22
+ # Cleanup after ourselves
23
+ def clean_up
24
+ # Remove objects and executable unless told to keep them.
25
+ unless @options[:keep]
26
+ File.delete(@output) if File.exists?(@output)
27
+
28
+ @options[:objs].each do |file|
29
+ File.delete(file) if File.exists?(file)
30
+ end
31
+ end
32
+
33
+ # Remove listing files unless they were requested.
34
+ unless @options[:list]
35
+ @options[:objs].each do |file|
36
+ file = change_type(file, ".lst")
37
+ File.delete(file) if File.exists?(file)
38
+ end
39
+ end
40
+
41
+ # Remove the map file if needed.
42
+ File.delete(@map_file) if !@options[:map] && File.exists?(@map_file)
43
+ end
44
+
45
+ end
@@ -0,0 +1,66 @@
1
+ # Process the command line arguments for the test65 program.
2
+
3
+ module Test65
4
+ # Process the command line arguments.
5
+ def self.process_args
6
+ @options = {}
7
+
8
+ opts = GetoptLong.new(
9
+ ["--debug", "-d", GetoptLong::NO_ARGUMENT],
10
+ ["--help", "-h", "-?", GetoptLong::NO_ARGUMENT],
11
+ ["--list", "-l", GetoptLong::NO_ARGUMENT],
12
+ ["--map", "-m", GetoptLong::NO_ARGUMENT],
13
+ ["--keep", "-k", GetoptLong::NO_ARGUMENT],
14
+ ["--path", "-p", GetoptLong::REQUIRED_ARGUMENT],
15
+ ["--quiet", "-q", GetoptLong::NO_ARGUMENT],
16
+ ["--verbose", "-v", GetoptLong::NO_ARGUMENT],
17
+ ["--version", GetoptLong::NO_ARGUMENT])
18
+
19
+ opts.each do |opt, arg|
20
+ case opt
21
+ when "--debug"
22
+ @options[:debug] = true
23
+ when "--help"
24
+ puts IO.read(@gem_root + "/help.txt")
25
+ exit
26
+ when "--keep"
27
+ @options[:keep] = true
28
+ when "--list"
29
+ @options[:list] = true
30
+ when "--map"
31
+ @options[:map] = true
32
+ when "--path"
33
+ unless @options[:path]
34
+ @options[:path] = File.absolute_path(arg.standardize_path)
35
+ else
36
+ fail "Multiple path options are not allowed."
37
+ end
38
+ when "--quiet"
39
+ @options[:quiet] = "2> _kwhyit"
40
+ when "--verbose"
41
+ @options[:verbose] = true
42
+ when "--version"
43
+ puts "test65 Version #{VERSION}"
44
+ exit
45
+ else
46
+ fail "Invalid option: #{opt}"
47
+ end
48
+ end
49
+
50
+ # A list of files to test may follow the options.
51
+ @arg_files = ARGV
52
+
53
+ # Setup some default paths
54
+ @options[:gem_root] = @gem_root
55
+ @options[:ca65_paths] = @gem_root + "/asminc"
56
+ @options[:cc65_home] = @cc65_home
57
+
58
+ rescue => err
59
+ puts "Error: #{err.to_s}"
60
+ puts err.backtrace if @options[:debug]
61
+ puts
62
+ puts IO.read(@gem_root + "/help.txt")
63
+ exit
64
+ end
65
+
66
+ end
@@ -0,0 +1,48 @@
1
+ # Process the test files.
2
+
3
+ module Test65
4
+
5
+ # Process the list of files
6
+ def self.process_file_list
7
+ @error_count = 0
8
+
9
+ @test_files.each do |file|
10
+ process_file(file)
11
+ end
12
+
13
+ if @error_count > 0
14
+ fail "#{@error_count} tests failed."
15
+ else
16
+ puts "OK: All tests passed."
17
+ end
18
+ end
19
+
20
+ # Process a file.
21
+ def self.process_file(file)
22
+ puts file.localize_path if @options[:verbose]
23
+
24
+ case File.extname(file)
25
+ when ".a65"
26
+ script { ca65(File.basename(file)); ld65; sim65 }
27
+
28
+ when ".rb"
29
+ load file
30
+
31
+ else
32
+ fail "Don't know how to process #{file}"
33
+ end
34
+ end
35
+
36
+ # Process a test script.
37
+ def self.script(&block)
38
+ test_script = TestScript.new(@options)
39
+ test_script.instance_exec(&block)
40
+ rescue => err
41
+ puts err
42
+ puts err.backtrace if @options[:debug]
43
+ @error_count += 1
44
+ ensure
45
+ test_script.clean_up
46
+ end
47
+
48
+ end
@@ -0,0 +1,36 @@
1
+ # Process the path to the test files.
2
+
3
+ module Test65
4
+
5
+ # Determine the path to test files.
6
+ def self.process_path
7
+ path = @options[:path] || get_default_path
8
+
9
+ localized_path = path.localize_path
10
+ fail "Path #{localized_path} does not exist." unless File.exists?(path)
11
+ fail "Path #{localized_path} is not a folder." unless File.directory?(path)
12
+ puts "Using path: #{localized_path}" if @options[:verbose]
13
+
14
+ @options[:path] = path
15
+ end
16
+
17
+ # Get the default test file path if one was not supplied.
18
+ def self.get_default_path
19
+ search, parent = Pathname.new(Dir.pwd), nil
20
+
21
+ while true
22
+ test = search.to_s + "/t65"
23
+
24
+ if File.exists?(test)
25
+ return test if File.directory?(test)
26
+ fail "The file #{local_path(test)} is not a folder."
27
+ end
28
+
29
+ search, parent = search.parent, search
30
+
31
+ fail "Default path not found." if search == parent
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,15 @@
1
+ # Portable path handling methods for the Test65 program.
2
+
3
+ class String
4
+
5
+ # Convert a path into standard form.
6
+ def standardize_path
7
+ self.gsub("\\", "/")
8
+ end
9
+
10
+ # Convert a path string into local system form.
11
+ def localize_path
12
+ windows? ? self.gsub("/", "\\") : self
13
+ end
14
+
15
+ end
@@ -0,0 +1,5 @@
1
+ module Test65
2
+ VERSION = "0.5.0".freeze
3
+
4
+ DESCRIPTION = "test65: A testing framework for ca65.".freeze
5
+ end
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
11
+
12
+ desc "What version of test65 is this?"
13
+ task :vers do |t|
14
+ puts
15
+ puts "test65 version = #{::Test65::VERSION}"
16
+ end
@@ -0,0 +1,12 @@
1
+ ; See how we deal with an assembly error.
2
+
3
+ .import exit:absolute
4
+ .export _main
5
+
6
+ .pc02
7
+
8
+ .code
9
+
10
+ _main:
11
+ lad #0 ; Deliberate error
12
+ jmp exit
@@ -0,0 +1,14 @@
1
+ ; Test a script with multiple objects
2
+
3
+ .export add_two:absolute
4
+ .pc02
5
+ .code
6
+
7
+ .ifdef do_add_two
8
+
9
+ add_two:
10
+ clc
11
+ adc #2
12
+ rts
13
+
14
+ .endif
@@ -0,0 +1,17 @@
1
+ ; Test a script with multiple objects
2
+ .include "test65.i65"
3
+
4
+ .import exit:absolute
5
+ .import add_two:absolute
6
+ .export _main
7
+
8
+ .pc02
9
+
10
+ .code
11
+
12
+ _main:
13
+ lda #10
14
+ jsr add_two
15
+ cmp #12
16
+ fail_ne 10
17
+ tests_pass
@@ -0,0 +1,3 @@
1
+ See how we deal with a nonsense file.
2
+ foo foo foo foo foo foo
3
+ bar bar bar bar bar bar
@@ -0,0 +1,13 @@
1
+ ; See how we deal with a linker error.
2
+
3
+ .import exit:absolute
4
+ .import an_error:absolute
5
+ .export _main
6
+
7
+ .pc02
8
+
9
+ .code
10
+
11
+ _main:
12
+ lda an_error
13
+ jmp exit
@@ -0,0 +1,11 @@
1
+ ; Test detecting an invalid err code.
2
+
3
+ .include "test65.i65"
4
+ .export _main
5
+ .pc02
6
+
7
+ .code
8
+
9
+ _main:
10
+ tests_fail 1
11
+ tests_pass
@@ -0,0 +1,12 @@
1
+ ; Test detecting an non-constant err code.
2
+
3
+ .include "test65.i65"
4
+ .export _main
5
+ .import an_error
6
+ .pc02
7
+
8
+ .code
9
+
10
+ _main:
11
+ tests_fail an_error
12
+ tests_pass
@@ -0,0 +1,12 @@
1
+ ; Minimum code that fails a test
2
+
3
+ .import exit:absolute
4
+ .export _main
5
+
6
+ .pc02
7
+
8
+ .code
9
+
10
+ _main:
11
+ lda #$ff
12
+ jmp exit
@@ -0,0 +1,12 @@
1
+ ; Minimum code that passes a test
2
+
3
+ .import exit:absolute
4
+ .export _main
5
+
6
+ .pc02
7
+
8
+ .code
9
+
10
+ _main:
11
+ lda #0
12
+ jmp exit
@@ -0,0 +1,9 @@
1
+ # Minimum script to pass a test.
2
+
3
+ Test65.script do
4
+
5
+ ca65 "min_pass.a65"
6
+ ld65
7
+ sim65
8
+
9
+ end
@@ -0,0 +1,10 @@
1
+ ; Minimum code that passes a test
2
+
3
+ .include "test65.i65"
4
+ .export _main
5
+ .pc02
6
+
7
+ .code
8
+
9
+ _main:
10
+ tests_pass
@@ -0,0 +1,9 @@
1
+ # Minimum script to pass a test.
2
+
3
+ Test65.script do
4
+
5
+ ca65 "min_pass.a65"
6
+ ld65
7
+ sim65
8
+
9
+ end
@@ -0,0 +1,13 @@
1
+ ; Minimum code that passes a test
2
+
3
+ .include "test65.i65"
4
+ .export _main
5
+ .pc02
6
+
7
+ .zeropage
8
+ mem1: .res 32
9
+
10
+ .code
11
+
12
+ _main:
13
+ tests_pass
@@ -0,0 +1,37 @@
1
+ ; Test a whole bunch of macros!
2
+
3
+ .include "test65.i65"
4
+ .export _main
5
+ .pc02
6
+
7
+ .code
8
+
9
+ _main:
10
+ lda #$00
11
+ fail_ne 10
12
+
13
+ inc
14
+ fail_eq 20
15
+ fail_mi 30
16
+
17
+ dec
18
+ dec
19
+ fail_pl 40
20
+
21
+ clc
22
+ adc #$02
23
+ fail_cc 50
24
+
25
+ clc
26
+ adc #$00
27
+ fail_cs 60
28
+
29
+ clv
30
+ fail_vs 70
31
+
32
+ lda #$70
33
+ clc
34
+ adc #$70
35
+ fail_vc 80
36
+
37
+ tests_pass
@@ -0,0 +1,10 @@
1
+ # Test a script with two source files.
2
+
3
+ Test65.script do
4
+
5
+ ca65 "caller.a65"
6
+ ca65 "callee.a65", "-D do_add_two"
7
+ ld65
8
+ sim65
9
+
10
+ end
@@ -0,0 +1,31 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "test65/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "test65"
7
+ spec.version = Test65::VERSION
8
+ spec.authors = ["PeterCamilleri"]
9
+ spec.email = ["peter.c.camilleri@gmail.com"]
10
+
11
+ spec.summary = Test65::DESCRIPTION
12
+ spec.description = "A testing framework for work on the Commander X 16."
13
+ spec.homepage = "https://github.com/PeterCamilleri/test65"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|docs)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec
21
+ .files
22
+ .reject { |f| f.downcase == 'exe/readme.md'}
23
+ .grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_runtime_dependency "full_dup"
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.17"
29
+ spec.add_development_dependency "rake", ">= 12.3.3"
30
+ spec.add_development_dependency "minitest", "~> 5.0"
31
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: test65
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - PeterCamilleri
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-06-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: full_dup
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.17'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.17'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 12.3.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ description: A testing framework for work on the Commander X 16.
70
+ email:
71
+ - peter.c.camilleri@gmail.com
72
+ executables:
73
+ - test65
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - CODE_OF_CONDUCT.md
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - asminc/test65.i65
83
+ - cfg/test65.cfg
84
+ - exe/test65
85
+ - help.txt
86
+ - lib/test65.rb
87
+ - lib/test65/build_file_list.rb
88
+ - lib/test65/enclosures/ca65.rb
89
+ - lib/test65/enclosures/ld65.rb
90
+ - lib/test65/enclosures/sim65.rb
91
+ - lib/test65/enclosures/utils.rb
92
+ - lib/test65/host.rb
93
+ - lib/test65/perform_test.rb
94
+ - lib/test65/process_args.rb
95
+ - lib/test65/process_files.rb
96
+ - lib/test65/process_path.rb
97
+ - lib/test65/std_path.rb
98
+ - lib/test65/version.rb
99
+ - rakefile.rb
100
+ - t65/asm_err.a65
101
+ - t65/callee.a65
102
+ - t65/caller.a65
103
+ - t65/foo.txt
104
+ - t65/linker_err.a65
105
+ - t65/macro_err1.a65
106
+ - t65/macro_err2.a65
107
+ - t65/min_fail.a65
108
+ - t65/min_pass.a65
109
+ - t65/min_pass.rb
110
+ - t65/pass.a65
111
+ - t65/t65_min_pass.rb
112
+ - t65/t65_test_cfg.a65
113
+ - t65/t65_test_macros.a65
114
+ - t65/t65_two_files.rb
115
+ - test65.gemspec
116
+ homepage: https://github.com/PeterCamilleri/test65
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.5.2
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: 'test65: A testing framework for ca65.'
140
+ test_files: []