spec/punchblock/component/output_spec.rb in punchblock-1.9.4 vs spec/punchblock/component/output_spec.rb in punchblock-2.0.0.beta1

- old
+ new

@@ -4,11 +4,11 @@ module Punchblock module Component describe Output do it 'registers itself' do - RayoNode.class_from_registration(:output, 'urn:xmpp:rayo:output:1').should be == Output + RayoNode.class_from_registration(:output, 'urn:xmpp:rayo:output:1').should be == described_class end describe 'default values' do its(:interrupt_on) { should be nil } its(:start_offset) { should be nil } @@ -16,128 +16,255 @@ its(:repeat_interval) { should be nil } its(:repeat_times) { should be nil } its(:max_time) { should be nil } its(:voice) { should be nil } its(:renderer) { should be nil } + its(:render_documents) { should be == [] } end + def ssml_doc(mode = :ordinal) + RubySpeech::SSML.draw do + say_as(:interpret_as => mode) { string '100' } + end + end + describe "when setting options in initializer" do subject do - Output.new :interrupt_on => :speech, + Output.new :interrupt_on => :voice, :start_offset => 2000, :start_paused => false, :repeat_interval => 2000, :repeat_times => 10, :max_time => 30000, :voice => 'allison', - :renderer => 'swift' + :renderer => 'swift', + :render_document => {:value => ssml_doc} end - its(:interrupt_on) { should be == :speech } + its(:interrupt_on) { should be == :voice } its(:start_offset) { should be == 2000 } its(:start_paused) { should be == false } its(:repeat_interval) { should be == 2000 } its(:repeat_times) { should be == 10 } its(:max_time) { should be == 30000 } its(:voice) { should be == 'allison' } its(:renderer) { should be == 'swift' } + its(:render_documents) { should be == [Output::Document.new(:value => ssml_doc)] } + + context "using #ssml=" do + subject do + Output.new :ssml => ssml_doc + end + + its(:render_documents) { should be == [Output::Document.new(:value => ssml_doc)] } + end + + context "with multiple documents" do + subject do + Output.new :render_documents => [ + {:value => ssml_doc}, + {:value => ssml_doc(:cardinal)} + ] + end + + its(:render_documents) { should be == [ + Output::Document.new(:value => ssml_doc), + Output::Document.new(:value => ssml_doc(:cardinal)) + ]} + end + + context "with a urilist" do + subject do + Output.new render_document: { + content_type: 'text/uri-list', + value: Punchblock::URIList.new('http://example.com/hello.mp3') + } + end + + its(:render_documents) { should be == [Output::Document.new(content_type: 'text/uri-list', value: ['http://example.com/hello.mp3'])] } + + describe "exporting to Rayo" do + it "should export to XML that can be understood by its parser" do + puts subject.to_rayo.to_xml + new_instance = RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root + new_instance.render_documents.should be == [Output::Document.new(content_type: 'text/uri-list', value: ['http://example.com/hello.mp3'])] + end + end + end + + context "with a nil document" do + it "removes all documents" do + subject.render_document = nil + subject.render_documents.should == [] + end + end + + context "without any documents" do + subject { described_class.new } + + its(:render_documents) { should == [] } + end + + describe "exporting to Rayo" do + it "should export to XML that can be understood by its parser" do + new_instance = RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root + new_instance.should be_instance_of described_class + new_instance.interrupt_on.should be == :voice + new_instance.start_offset.should be == 2000 + new_instance.start_paused.should be == false + new_instance.repeat_interval.should be == 2000 + new_instance.repeat_times.should be == 10 + new_instance.max_time.should be == 30000 + new_instance.voice.should be == 'allison' + new_instance.renderer.should be == 'swift' + new_instance.render_documents.should be == [Output::Document.new(:value => ssml_doc)] + end + + it "should wrap the document value in CDATA" do + grammar_node = subject.to_rayo.at_xpath('ns:document', ns: described_class.registered_ns) + grammar_node.children.first.should be_a Nokogiri::XML::CDATA + end + + it "should render to a parent node if supplied" do + doc = Nokogiri::XML::Document.new + parent = Nokogiri::XML::Node.new 'foo', doc + doc.root = parent + rayo_doc = subject.to_rayo(parent) + rayo_doc.should == parent + end + end end describe "from a stanza" do let :stanza do <<-MESSAGE <output xmlns='urn:xmpp:rayo:output:1' - interrupt-on='speech' + interrupt-on='voice' start-offset='2000' start-paused='false' repeat-interval='2000' repeat-times='10' max-time='30000' voice='allison' - renderer='swift'>Hello world</output> + renderer='swift'> + <document content-type="application/ssml+xml"> + <![CDATA[ + <speak version="1.0" + xmlns="http://www.w3.org/2001/10/synthesis" + xml:lang="en-US"> + <say-as interpret-as="ordinal">100</say-as> + </speak> + ]]> + </document> + <document content-type="application/ssml+xml"> + <![CDATA[ + <speak version="1.0" + xmlns="http://www.w3.org/2001/10/synthesis" + xml:lang="en-US"> + <say-as interpret-as="ordinal">100</say-as> + </speak> + ]]> + </document> +</output> MESSAGE end - subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' } + subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' } it { should be_instance_of Output } - its(:interrupt_on) { should be == :speech } + its(:interrupt_on) { should be == :voice } its(:start_offset) { should be == 2000 } its(:start_paused) { should be == false } its(:repeat_interval) { should be == 2000 } its(:repeat_times) { should be == 10 } its(:max_time) { should be == 30000 } its(:voice) { should be == 'allison' } its(:renderer) { should be == 'swift' } - its(:text) { should be == 'Hello world' } + its(:render_documents) { should be == [Output::Document.new(:value => ssml_doc), Output::Document.new(:value => ssml_doc)] } - context "with SSML" do + context "with a urilist" do let :stanza do <<-MESSAGE -<output xmlns='urn:xmpp:rayo:output:1' - interrupt-on='speech' - start-offset='2000' - start-paused='false' - repeat-interval='2000' - repeat-times='10' - max-time='30000' - voice='allison' - renderer='swift'> - <speak version="1.0" - xmlns="http://www.w3.org/2001/10/synthesis" - xml:lang="en-US"> - <say-as interpret-as="ordinal">100</say-as> - </speak> +<output xmlns='urn:xmpp:rayo:output:1'> + <document content-type="text/uri-list"> + <![CDATA[ + http://example.com/hello.mp3 + http://example.com/goodbye.mp3 + ]]> + </document> </output> MESSAGE end - def ssml_doc(mode = :ordinal) - RubySpeech::SSML.draw do - say_as(:interpret_as => mode) { string '100' } - end - end - - its(:ssml) { should be == ssml_doc } + its(:render_documents) { should be == [Output::Document.new(content_type: 'text/uri-list', value: ['http://example.com/hello.mp3', 'http://example.com/goodbye.mp3'])] } end end - describe "for text" do - subject { Output.new :text => 'Once upon a time there was a message...', :voice => 'kate' } + describe Output::Document do + describe "when not passing a content type" do + subject { Output::Document.new :value => ssml_doc } + its(:content_type) { should be == 'application/ssml+xml' } + end - its(:voice) { should be == 'kate' } - its(:text) { should be == 'Once upon a time there was a message...' } - end + describe 'with an SSML document' do + subject { Output::Document.new :value => ssml_doc, :content_type => 'application/ssml+xml' } - describe "for SSML" do - def ssml_doc(mode = :ordinal) - RubySpeech::SSML.draw do - say_as(:interpret_as => mode) { string '100' } + its(:content_type) { should be == 'application/ssml+xml' } + + its(:value) { should be == ssml_doc } + + describe "comparison" do + let(:document2) { Output::Document.new :value => ssml_doc } + let(:document3) { Output::Document.new :value => ssml_doc(:normal) } + + it { should be == document2 } + it { should_not be == document3 } end end - subject { Output.new :ssml => ssml_doc, :voice => 'kate' } + describe 'with a urilist' do + subject { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/hello.mp3', 'http://example.com/goodbye.mp3') } - its(:voice) { should be == 'kate' } + its(:value) { should be == Punchblock::URIList.new('http://example.com/hello.mp3', 'http://example.com/goodbye.mp3') } - its(:ssml) { should be == ssml_doc } + describe "comparison" do + let(:document2) { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/hello.mp3', 'http://example.com/goodbye.mp3') } + let(:document3) { Output::Document.new value: '<speak xmlns="http://www.w3.org/2001/10/synthesis" version="1.0" xml:lang="en-US"><say-as interpret-as="ordinal">100</say-as></speak>' } + let(:document4) { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/hello.mp3') } + let(:document5) { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/goodbye.mp3', 'http://example.com/hello.mp3') } - describe "comparison" do - let(:output2) { Output.new :ssml => '<speak xmlns="http://www.w3.org/2001/10/synthesis" version="1.0" xml:lang="en-US"><say-as interpret-as="ordinal">100</say-as></speak>', :voice => 'kate' } - let(:output3) { Output.new :ssml => ssml_doc, :voice => 'kate' } - let(:output4) { Output.new :ssml => ssml_doc(:normal), :voice => 'kate' } + it { should be == document2 } + it { should_not be == document3 } + it { should_not be == document4 } + it { should_not be == document5 } + end + end - it { should be == output2 } - it { should be == output3 } - it { should_not be == output4 } + describe 'with a document reference by URL' do + let(:url) { 'http://foo.com/bar.grxml' } + + subject { Output::Document.new :url => url } + + its(:url) { should be == url } + its(:content_type) { should be nil} + + describe "comparison" do + it "should be the same with the same url" do + Output::Document.new(:url => url).should be == Output::Document.new(:url => url) + end + + it "should be different with a different url" do + Output::Document.new(:url => url).should_not be == Output::Document.new(:url => 'http://doo.com/dah') + end + end end end describe "actions" do - let(:mock_client) { mock 'Client' } - let(:command) { Output.new :text => 'Once upon a time there was a message...', :voice => 'kate' } + let(:mock_client) { double 'Client' } + let(:command) { described_class.new } before do command.component_id = 'abc123' command.target_call_id = '123abc' command.client = mock_client @@ -594,22 +721,27 @@ end end end end - describe Output::Complete::Success do - let :stanza do - <<-MESSAGE + { + Output::Complete::Finish => :finish, + Output::Complete::MaxTime => :'max-time', + }.each do |klass, element_name| + describe klass do + let :stanza do + <<-MESSAGE <complete xmlns='urn:xmpp:rayo:ext:1'> -<success xmlns='urn:xmpp:rayo:output:complete:1' /> +<#{element_name} xmlns='urn:xmpp:rayo:output:complete:1' /> </complete> - MESSAGE - end + MESSAGE + end - subject { RayoNode.import(parse_stanza(stanza).root).reason } + subject { RayoNode.from_xml(parse_stanza(stanza).root).reason } - it { should be_instance_of Output::Complete::Success } + it { should be_instance_of klass } - its(:name) { should be == :success } + its(:name) { should be == element_name } + end end end -end # Punchblock +end