Add test coverage for a bunch of stuff.

This commit is contained in:
James Harton 2020-03-31 20:45:55 +13:00
parent 3658529772
commit a7cb693849
44 changed files with 651 additions and 116 deletions

View file

@ -9,3 +9,5 @@ gem 'pry', '~> 0.13.0'
gem 'rake', '~> 12.0'
gem 'rspec', '~> 3.0'
gem 'rubocop', '~> 0.80.1'
gem 'faker', '~> 2.11'

View file

@ -9,8 +9,13 @@ GEM
specs:
ast (2.4.0)
coderay (1.1.2)
concurrent-ruby (1.1.6)
diff-lcs (1.3)
dry-inflector (0.2.0)
faker (2.11.0)
i18n (>= 1.6, < 2)
i18n (1.8.2)
concurrent-ruby (~> 1.0)
jaro_winkler (1.5.4)
method_source (1.0.0)
parallel (1.19.1)
@ -50,6 +55,7 @@ PLATFORMS
ruby
DEPENDENCIES
faker (~> 2.11)
pry (~> 0.13.0)
rake (~> 12.0)
rspec (~> 3.0)

View file

@ -15,10 +15,10 @@ module WAG
require 'wag/export'
require 'wag/f32_instructions'
require 'wag/f64_instructions'
require 'wag/function_type'
require 'wag/function'
require 'wag/global'
require 'wag/function_type'
require 'wag/global_instructions'
require 'wag/global'
require 'wag/i32_instructions'
require 'wag/i64_instructions'
require 'wag/import'
@ -26,6 +26,7 @@ module WAG
require 'wag/instruction'
require 'wag/label'
require 'wag/local_instructions'
require 'wag/memory_instructions'
require 'wag/memory'
require 'wag/module'
require 'wag/param'

View file

@ -20,14 +20,14 @@ module WAG
@desc = Global.new(label, type)
end
def memory(number, min: nil, max: nil, &block)
@desc = Memory.new(number, min: min, max: max)
def memory(number, min = nil, max = nil, &block)
@desc = Memory.new(number, min, max)
@desc.instance_exec(&block) if block
@desc
end
def table(number, type = :funcref, min: nil, max: nil, &block)
@desc = Table.new(number, type, min: min, max: max)
def table(number, type = :funcref, &block)
@desc = Table.new(number, type)
@desc.instance_exec(&block) if block
@desc
end

View file

@ -11,7 +11,7 @@ module WAG
convert_i64_s convert_i64_u reinterpret_i32].each do |instruction_name|
camelised_name = "F32#{WAG::Inflector.inflector.camelize(instruction_name)}"
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
@instructions << instruction
instruction.instance_exec(&block) if block
instruction

View file

@ -11,7 +11,7 @@ module WAG
convert_i64_s convert_i64_u promote_f32 reinterpret_i64].each do |instruction_name|
camelised_name = "F64#{WAG::Inflector.inflector.camelize(instruction_name)}"
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
@instructions << instruction
instruction.instance_exec(&block) if block
instruction

View file

@ -7,8 +7,8 @@ module WAG
attr_reader :label, :params
def initialize(label)
@label = WAG::Label.from(label)
def initialize(label = nil)
@label = WAG::Label.from(label) if label
@params = []
end
@ -23,7 +23,8 @@ module WAG
end
def to_sexpr
[:func, @label.to_sexpr].tap do |func|
[:func].tap do |func|
func.push(@label.to_sexpr) if @label
func.concat(@params.map(&:to_sexpr)) unless @params.empty?
func.push(@result.to_sexpr) if @result
end

View file

@ -1,31 +1,16 @@
# frozen_string_literal: true
module WAG
class FunctionType
include WAG::WAT
attr_reader :label, :params, :results
def initialize(label)
@label = WAG::Label.from(label)
@params = []
@results = []
end
def param(*types)
@params.concat(types.map { |t| WAG::Type.from(t) })
end
def result(*types)
@results.concat(types.map { |t| WAG::Type.from(t) })
end
class FunctionType < Function
def to_sexpr
[:type, @label.to_sexpr,
[:func].tap do |func|
func.push([:param].concat(@params.map(&:to_sexpr))) if @params
func.push([:result].concat(@results.map(&:to_sexpr))) if @results
end]
[:type].tap do |type|
type.push(@label.to_sexpr) if @label
[:func].tap do |func|
func.concat(@params.map(&:to_sexpr)) unless @params.empty?
func.push(@result.to_sexpr) if @result
type.push(func)
end
end
end
end
end

View file

@ -7,9 +7,9 @@ module WAG
end
%i[get set].each do |instruction_name|
camelised_name = "Global#{WAG::Inflector.inflector.camelize(instruction_name)}"
camelised_name = "Global::#{WAG::Inflector.inflector.camelize(instruction_name)}"
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
@instructions << instruction
instruction.instance_exec(&block) if block
instruction

View file

@ -10,9 +10,9 @@ module WAG
ne lt_s lt_u gt_s gt_u le_s le_u ge_s ge_u clz ctz popcnt add sub mul
div_s div_u rem_s rem_u and or xor shl shr_s shr_u rotl rotr trunc_f32_s
trunc_f32_u trunc_f64_s trunc_f64_u reinterpret_f32].each do |instruction_name|
camelised_name = "I32#{WAG::Inflector.inflector.camelize(instruction_name)}"
camelised_name = "I32::#{WAG::Inflector.inflector.camelize(instruction_name)}"
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
@instructions << instruction
instruction.instance_exec(&block) if block
instruction

View file

@ -9,11 +9,11 @@ module WAG
%i[load load8_s load8_u load16_s load16_u load32_s load32_u store store8
store16 store32 const eqz eq ne lt_s lt_u gt_s gt_u le_s le_u ge_s ge_u
clz ctz popcnt add sub mul div_s div_u rem_s rem_u and or xor shl shr_s
shr_u rotl rotr extend_i13_s extend_i32_u trunc_f32_s trunc_f32_u
shr_u rotl rotr extend_i32_s extend_i32_u trunc_f32_s trunc_f32_u
trunc_f64_s trunc_f64_u reinterpret_f64].each do |instruction_name|
camelised_name = "I32#{WAG::Inflector.inflector.camelize(instruction_name)}"
camelised_name = "I64::#{WAG::Inflector.inflector.camelize(instruction_name)}"
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
@instructions << instruction
instruction.instance_exec(&block) if block
instruction

View file

@ -23,14 +23,14 @@ module WAG
@desc
end
def memory(number, min: nil, max: nil, &block)
@desc = Memory.new(number, min: min, max: max)
def memory(number, min = nil, max = nil, &block)
@desc = Memory.new(number, min, max)
@desc.instance_exec(&block) if block
@desc
end
def table(number, type = :funcref, min: nil, max: nil, &block)
@desc = Table.new(number, type, min: min, max: max)
def table(number, type = :funcref, &block)
@desc = Table.new(number, type)
@desc.instance_exec(&block) if block
@desc
end

View file

@ -7,13 +7,21 @@ module WAG
call_indirect drop select].each do |instruction_name|
camelised_name = WAG::Inflector.inflector.camelize(instruction_name)
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
instructions << instruction
instruction.instance_exec(&block) if block
instruction
end
end
def f32
WAG::F32Instructions.new(instructions)
end
def f64
WAG::F64Instructions.new(instructions)
end
def local
WAG::LocalInstructions.new(instructions)
end

View file

@ -133,6 +133,7 @@ module WAG
require 'wag/instructions/i64/base'
require 'wag/instructions/i64/add'
require 'wag/instructions/i64/and'
require 'wag/instructions/i64/clz'
require 'wag/instructions/i64/const'
require 'wag/instructions/i64/ctz'

View file

@ -7,7 +7,7 @@ module WAG
prepend WAG::Instructable
def self.instruction(op_code)
klass = Class.new(WAG::Instruction::Base)
klass = Class.new(self)
klass.define_method(:op_code) { op_code }
klass
end

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
module WAG
module Instruction
module I64
class And < Base.instruction(0x7c)
end
end
end
end

View file

@ -7,9 +7,9 @@ module WAG
end
%i[get set tee].each do |instruction_name|
camelised_name = "Local#{WAG::Inflector.inflector.camelize(instruction_name)}"
camelised_name = "Local::#{WAG::Inflector.inflector.camelize(instruction_name)}"
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
@instructions << instruction
instruction.instance_exec(&block) if block
instruction

View file

@ -6,19 +6,19 @@ module WAG
attr_reader :number, :min, :max
def initialize(number, min: nil, max: nil)
def initialize(number, min = nil, max = nil)
@number = number
@min = min
@max = max
end
def to_sexpr
wat = [:memory, number]
wat.concat([:min, min]) if min
wat.concat([:max, max]) if max
wat
[:memory, number].tap do |expr|
if min
expr.push(min)
expr.push(max) if max
end
end
end
end
end

View file

@ -7,9 +7,9 @@ module WAG
end
%i[size grow].each do |instruction_name|
camelised_name = "Memory#{WAG::Inflector.inflector.camelize(instruction_name)}"
camelised_name = "Memory::#{WAG::Inflector.inflector.camelize(instruction_name)}"
define_method(instruction_name) do |*args, &block|
instruction = WAG::Instruction.get_const(camelised_name).new(*args)
instruction = WAG::Instruction.const_get(camelised_name).new(*args)
@instructions << instruction
instruction.instance_exec(&block) if block
instruction

View file

@ -29,8 +29,8 @@ module WAG
export
end
def memory(number, min: nil, max: nil, &block)
mem = Memory.new(number, min: min, max: max)
def memory(number, min = nil, max = nil, &block)
mem = Memory.new(number, min, max)
@memories << mem
mem.instance_exec(&block) if block
mem
@ -63,7 +63,7 @@ module WAG
data
end
def func(label, &block)
def func(label = nil, &block)
func = Function.new(label)
@functions << func
func.instance_exec(&block) if block

View file

@ -3,27 +3,15 @@
module WAG
class Table
include WAG::WAT
attr_reader :elements, :type
RANGE = (0..0xFFFFFFFF).freeze
attr_reader :number, :type, :min, :max
def initialize(number, type = :funcref, min: nil, max: nil) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
raise '`min` must fit in i32 range' if min && !RANGE.cover?(min)
raise '`max` must fit in i32 range' if max && !RANGE.cover?(max)
raise '`max` must be greater than `min`' if min && max && min > max
@number = number
def initialize(elements, type = :funcref)
@elements = elements
@type = type
@min = min
@max = max
end
def to_sexpr
expr = [:table, number, type]
expr.concat([:min, min]) if min
expr.concat([:max, max]) if max
expr
[:table, elements, type]
end
end
end

View file

@ -3,10 +3,10 @@
module WAG
module Type
require 'wag/types/base'
require 'wag/types/i32'
require 'wag/types/i64'
require 'wag/types/f32'
require 'wag/types/f64'
require 'wag/types/i32'
require 'wag/types/i64'
module_function

View file

@ -1,28 +0,0 @@
# frozen_string_literal: true
module WAG
module Type
# A WebAssembly function type.
class Function < Base
attr_reader :parameter_types, :return_types
def initialize(parameter_types, return_types)
parameter_types.map! { |t| Huia::Type.from(t) }
return_types.map! { |t| Huia::Type.from(t) }
raise 'There must only be one return type (at the moment)' unless return_types.one?
unless parameter_types.all?(&:value?) && return_types.all?(&:value?)
raise 'Function type parameters can only be value types'
end
@parameter_types = parameter_types
@return_types = return_types
end
def value?
false
end
end
end
end

View file

@ -3,6 +3,7 @@
require 'bundler/setup'
require 'wag'
require 'pry'
require 'faker'
RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure

View file

@ -8,23 +8,23 @@ RSpec.describe WAG::Export do
describe 'When exporting memory' do
before do
export.memory(1, min: 1, max: 64)
export.memory(1, 1, 64)
end
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq [:export, 'marty', [:memory, 1, :min, 1, :max, 64]] }
it { is_expected.to eq [:export, 'marty', [:memory, 1, 1, 64]] }
end
end
describe 'When exporting a table' do
before do
export.table(1, :funcref, min: 1, max: 64)
export.table(1, :funcref)
end
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq [:export, 'marty', [:table, 1, :funcref, :min, 1, :max, 64]] }
it { is_expected.to eq [:export, 'marty', [:table, 1, :funcref]] }
end
end

80
spec/wag/function_spec.rb Normal file
View file

@ -0,0 +1,80 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Function do
let(:label) { Faker::Name.first_name }
let(:function) { described_class.new(label) }
subject { function }
describe 'When the function is given a label' do
let(:label) { Faker::Name.first_name }
it 'correctly sets the label' do
expect(subject.label.value).to eq label
end
end
describe '#param' do
let(:type) { :i32 }
subject { super().param(label, type) }
it 'adds the param to the function' do
expect { subject }
.to change { function.params.size }
.from(0)
.to(1)
end
it 'correctly sets the param' do
subject
expect(function.params.first).to be_a(WAG::Param)
expect(function.params.first.label.value).to eq(label)
expect(function.params.first.type).to be_a(WAG::Type::I32)
end
end
describe '#result' do
subject { super().result(:i32) }
it 'correctly sets the result' do
subject
expect(function.result).to be_a(WAG::Result)
expect(function.result.types.size).to eq(1)
expect(function.result.types.first).to be_a(WAG::Type::I32)
end
end
describe '#to_sexpr' do
subject { super().to_sexpr }
context 'When the function is empty' do
let(:label) { nil }
it { is_expected.to eq [:func] }
end
context 'When the function has a label' do
it { is_expected.to eq [:func, "$#{label}".to_sym] }
context 'And the function takes a parameter' do
before { function.param(:p0, :i32) }
it { is_expected.to eq [:func, "$#{label}".to_sym, %i[param $p0 i32]] }
context 'And the function takes a second parameter' do
before { function.param(:p1, :f32) }
it { is_expected.to eq [:func, "$#{label}".to_sym, %i[param $p0 i32], %i[param $p1 f32]] }
end
end
context 'When the function has a return type' do
before { function.result(:i64) }
it { is_expected.to eq [:func, "$#{label}".to_sym, %i[result i64]] }
end
context 'When the function has a body' do
before { function.i64.const(13) }
it { is_expected.to eq [:func, "$#{label}".to_sym, [:"i64.const", 13]] }
end
end
end
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::GlobalInstructions do
let(:label) { Faker::Name.first_name }
let(:instructions) { [] }
subject { described_class.new(instructions) }
%i[get set].each do |instruction_name|
describe "##{instruction_name}" do
subject { super().public_send(instruction_name, label) }
it "adds a `global.#{instruction_name}` to the instructions" do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::Global.const_get(WAG::Inflector.inflector.camelize(instruction_name)))
end
it 'sets the label correctly' do
subject
expect(instructions.first.label.value)
.to eq(label)
end
end
end
end

View file

@ -0,0 +1,47 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::I32Instructions do
let(:instructions) { [] }
subject { described_class.new(instructions) }
%i[load load8_s load8_u load16_s load16_u store store8 store16 eqz eq
ne lt_s lt_u gt_s gt_u le_s le_u ge_s ge_u clz ctz popcnt add sub mul
div_s div_u rem_s rem_u and or xor shl shr_s shr_u rotl rotr trunc_f32_s
trunc_f32_u trunc_f64_s trunc_f64_u reinterpret_f32].each do |instruction_name|
describe "##{instruction_name}" do
subject { super().public_send(instruction_name) }
it "adds a `i32.#{instruction_name}` to the instructions" do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::I32.const_get(WAG::Inflector.inflector.camelize(instruction_name)))
end
end
end
describe '#const' do
let(:value) { rand(0xFFFFFFFF) }
subject { super().const(value) }
it 'adds a `i32.const` to the instructions' do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::I32::Const)
end
it 'has the correct value' do
subject
expect(instructions.first.literal).to eq(value)
end
end
end

View file

@ -0,0 +1,48 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::I64Instructions do
let(:instructions) { [] }
subject { described_class.new(instructions) }
%i[load load8_s load8_u load16_s load16_u load32_s load32_u store store8
store16 store32 eqz eq ne lt_s lt_u gt_s gt_u le_s le_u ge_s ge_u
clz ctz popcnt add sub mul div_s div_u rem_s rem_u and or xor shl shr_s
shr_u rotl rotr extend_i32_s extend_i32_u trunc_f32_s trunc_f32_u
trunc_f64_s trunc_f64_u reinterpret_f64].each do |instruction_name|
describe "##{instruction_name}" do
subject { super().public_send(instruction_name) }
it "adds a `i64.#{instruction_name}` to the instructions" do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::I64.const_get(WAG::Inflector.inflector.camelize(instruction_name)))
end
end
end
describe '#const' do
let(:value) { rand(0xFFFFFFFFFFFFFFFF) }
subject { super().const(value) }
it 'adds a `i64.const` to the instructions' do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::I64::Const)
end
it 'has the correct value' do
subject
expect(instructions.first.literal).to eq(value)
end
end
end

View file

@ -8,23 +8,23 @@ RSpec.describe WAG::Import do
describe 'When importing memory' do
before do
import.memory(1, min: 1, max: 64)
import.memory(1, 1, 64)
end
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq [:import, 'marty', 'mcfly', [:memory, 1, :min, 1, :max, 64]] }
it { is_expected.to eq [:import, 'marty', 'mcfly', [:memory, 1, 1, 64]] }
end
end
describe 'When importing a table' do
before do
import.table(1, :funcref, min: 1, max: 64)
import.table(1, :funcref)
end
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq [:import, 'marty', 'mcfly', [:table, 1, :funcref, :min, 1, :max, 64]] }
it { is_expected.to eq [:import, 'marty', 'mcfly', [:table, 1, :funcref]] }
end
end

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Inflector do
describe '.inflector' do
subject { described_class.inflector }
it { is_expected.to be_a(Dry::Inflector) }
end
end

View file

@ -0,0 +1,59 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Instructable do
subject do
Class.new do
include WAG::Instructable
end.new
end
describe '.local' do
subject { super().local }
it { is_expected.to be_a(WAG::LocalInstructions) }
end
describe '#f32' do
subject { super().f32 }
it { is_expected.to be_a(WAG::F32Instructions) }
end
describe '#f64' do
subject { super().f64 }
it { is_expected.to be_a(WAG::F64Instructions) }
end
describe '#i32' do
subject { super().i32 }
it { is_expected.to be_a(WAG::I32Instructions) }
end
describe '#i64' do
subject { super().i64 }
it { is_expected.to be_a(WAG::I64Instructions) }
end
describe '#memory' do
subject { super().memory }
it { is_expected.to be_a(WAG::MemoryInstructions) }
end
%i[unreachable nop block loop if else end br_table return call
call_indirect drop select].each do |instruction_name|
describe "##{instruction_name}" do
subject { super().public_send(instruction_name) }
it { is_expected.to be_a(WAG::Instruction.const_get(WAG::Inflector.inflector.camelize(instruction_name))) }
end
end
%i[br br_if].each do |instruction_name|
describe "##{instruction_name}" do
let(:label) { Faker::Name.first_name }
subject { super().public_send(instruction_name, label) }
it { is_expected.to be_a(WAG::Instruction.const_get(WAG::Inflector.inflector.camelize(instruction_name))) }
end
end
end

31
spec/wag/label_spec.rb Normal file
View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Label do
let(:value) { Faker::Name.first_name }
subject { described_class.new(value) }
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq "$#{value}".to_sym }
end
describe '.from' do
subject { described_class.from(value) }
it { is_expected.to be_a(described_class) }
context 'When the value is a string' do
describe '#value' do
subject { super().value }
it { is_expected.to eq value }
end
end
context 'When the value is already a label' do
let(:value) { described_class.new(Faker::Name.first_name) }
it { is_expected.to eq value }
end
end
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::LocalInstructions do
let(:label) { Faker::Name.first_name }
let(:instructions) { [] }
subject { described_class.new(instructions) }
%i[get set tee].each do |instruction_name|
describe "##{instruction_name}" do
subject { super().public_send(instruction_name, label) }
it "adds a `local.#{instruction_name}` to the instructions" do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::Local.const_get(WAG::Inflector.inflector.camelize(instruction_name)))
end
it 'sets the label correctly' do
subject
expect(instructions.first.label.value)
.to eq(label)
end
end
end
end

View file

@ -0,0 +1,36 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::MemoryInstructions do
let(:instructions) { [] }
subject { described_class.new(instructions) }
describe '#size' do
subject { super().size }
it 'adds a `memory.size` to the instructions' do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::Memory::Size)
end
end
describe '#grow' do
subject { super().grow }
it 'adds a `memory.grow` to the instructions' do
expect { subject }
.to change { instructions.size }
.from(0)
.to(1)
expect(instructions.first)
.to be_a(WAG::Instruction::Memory::Grow)
end
end
end

28
spec/wag/memory_spec.rb Normal file
View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Memory do
let(:number) { rand(99) }
let(:min) { nil }
let(:max) { nil }
subject { described_class.new(number, min, max) }
describe '#to_sexpr' do
subject { super().to_sexpr }
describe 'When there is no minumum value' do
it { is_expected.to eq [:memory, number] }
end
describe 'When there is a minumum value' do
let(:min) { rand(99) }
it { is_expected.to eq [:memory, number, min] }
describe 'When there is a max value' do
let(:max) { min + rand(99) }
it { is_expected.to eq [:memory, number, min, max] }
end
end
end
end

22
spec/wag/param_spec.rb Normal file
View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Param do
let(:type) { :i32 }
subject { described_class.new(type, label) }
describe '#to_sexpr' do
subject { super().to_sexpr }
context 'When the param has a label' do
let(:label) { :foo }
it { is_expected.to eq %i[param $foo i32] }
end
context 'When the param has no label' do
let(:label) { nil }
it { is_expected.to eq %i[param i32] }
end
end
end

13
spec/wag/result_spec.rb Normal file
View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Result do
let(:types) { %i[i32 i64] }
subject { described_class.new(*types) }
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq %i[result i32 i64] }
end
end

13
spec/wag/table_spec.rb Normal file
View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Table do
let(:elements) { rand(99) }
subject { described_class.new(elements) }
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq [:table, elements, :funcref] }
end
end

63
spec/wag/type_spec.rb Normal file
View file

@ -0,0 +1,63 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Type do
describe '.from' do
subject { described_class.from(argument) }
context 'When the argument is `:f32`' do
let(:argument) { :f32 }
it { is_expected.to be_a(WAG::Type::F32) }
end
context 'When the argument is `:f64`' do
let(:argument) { :f64 }
it { is_expected.to be_a(WAG::Type::F64) }
end
context 'When the argument is `:i32`' do
let(:argument) { :i32 }
it { is_expected.to be_a(WAG::Type::I32) }
end
context 'When the argument is `:i64`' do
let(:argument) { :i64 }
it { is_expected.to be_a(WAG::Type::I64) }
end
context 'When the argument is a `WAG::Type::F32`' do
let(:argument) { WAG::Type::F32.new }
it { is_expected.to eq argument }
end
context 'When the argument is a `WAG::Type::F64`' do
let(:argument) { WAG::Type::F64.new }
it { is_expected.to eq argument }
end
context 'When the argument is a `WAG::Type::I32`' do
let(:argument) { WAG::Type::I32.new }
it { is_expected.to eq argument }
end
context 'When the argument is a `WAG::Type::I64`' do
let(:argument) { WAG::Type::I64.new }
it { is_expected.to eq argument }
end
context 'When the argument is an unknown symbol' do
let(:argument) { :marty_mcfly }
it 'raises a NameError' do
expect { subject }.to raise_error(NameError)
end
end
context 'When the argument is an unknown object' do
let(:argument) { WAG::Instruction::Nop.new }
it 'raises a NameError' do
expect { subject }.to raise_error(NameError)
end
end
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Type::F32 do
it { is_expected.to be_a(WAG::Type::Base) }
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq :f32 }
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Type::F64 do
it { is_expected.to be_a(WAG::Type::Base) }
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq :f64 }
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Type::I32 do
it { is_expected.to be_a(WAG::Type::Base) }
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq :i32 }
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WAG::Type::I64 do
it { is_expected.to be_a(WAG::Type::Base) }
describe '#to_sexpr' do
subject { super().to_sexpr }
it { is_expected.to eq :i64 }
end
end