From f13848cab284839c2f6abd39ef38dd18692a50cf Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sun, 7 Apr 2013 19:08:46 +0200 Subject: Even more conformance fixes --- contrib/ctest/CTestCustom.ctest.in | 13 ++++ contrib/dom/idl/SCXMLEvent.idl | 10 +-- contrib/dom/scripts/CodeGeneratorArabicaV8.pm | 4 ++ src/uscxml/Interpreter.cpp | 77 ++++++++++++++-------- src/uscxml/Interpreter.h | 22 +++---- src/uscxml/Message.h | 7 +- src/uscxml/interpreter/InterpreterDraft6.cpp | 3 +- .../datamodel/ecmascript/v8/V8DataModel.cpp | 5 +- .../datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp | 13 ++-- .../datamodel/ecmascript/v8/dom/V8SCXMLEvent.h | 4 +- .../ecmascript/v8/dom/V8SCXMLEventCustom.cpp | 11 +++- .../ioprocessor/basichttp/BasicHTTPIOProcessor.cpp | 2 +- .../plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp | 38 +++++++++-- test/src/test-w3c.cpp | 4 +- 14 files changed, 140 insertions(+), 73 deletions(-) diff --git a/contrib/ctest/CTestCustom.ctest.in b/contrib/ctest/CTestCustom.ctest.in index dd3aae6..fe63861 100644 --- a/contrib/ctest/CTestCustom.ctest.in +++ b/contrib/ctest/CTestCustom.ctest.in @@ -30,4 +30,17 @@ set(CTEST_CUSTOM_TESTS_IGNORE "test568.scxml" ) +# grep -ori 'manual' . +# manual tests +set(CTEST_CUSTOM_TESTS_IGNORE + ${CTEST_CUSTOM_TESTS_IGNORE} + "test178.scxml" + "test230.scxml" + "test250.scxml" + "test307.scxml" + "test313.scxml" + "test314.scxml" +) + + diff --git a/contrib/dom/idl/SCXMLEvent.idl b/contrib/dom/idl/SCXMLEvent.idl index 394aa1a..c94560b 100644 --- a/contrib/dom/idl/SCXMLEvent.idl +++ b/contrib/dom/idl/SCXMLEvent.idl @@ -7,11 +7,11 @@ const unsigned short EXTERNAL = 2; const unsigned short PLATFORM = 3; - [CustomGetter] readonly attribute DOMString type; + [CustomGetter, EmptyAsNull] readonly attribute DOMString type; readonly attribute DOMString name; - readonly attribute DOMString origin; - readonly attribute DOMString origintype; + [EmptyAsNull] readonly attribute DOMString origin; + [EmptyAsNull] readonly attribute DOMString origintype; readonly attribute Node dom; - readonly attribute DOMString sendid; - readonly attribute DOMString invokeid; + [CustomGetter] readonly attribute DOMString sendid; + [EmptyAsNull] readonly attribute DOMString invokeid; }; diff --git a/contrib/dom/scripts/CodeGeneratorArabicaV8.pm b/contrib/dom/scripts/CodeGeneratorArabicaV8.pm index 0c7d1b5..17c83f5 100644 --- a/contrib/dom/scripts/CodeGeneratorArabicaV8.pm +++ b/contrib/dom/scripts/CodeGeneratorArabicaV8.pm @@ -352,6 +352,10 @@ END } else { my $v8Type = IdlToV8Type($attrType); if ($attrType eq "DOMString") { + if ($attrExt->{'EmptyAsNull'}) { + push(@implContent, "\n if (privData->nativeObj->${wrapperGetter}.length() == 0)"); + push(@implContent, "\n return v8::Undefined();"); + } push(@implContent, "\n return ${v8Type}::New(privData->nativeObj->${wrapperGetter}.c_str());"); } else { push(@implContent, "\n return ${v8Type}::New(privData->nativeObj->${wrapperGetter});"); diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index ee1a3b9..9d6b764 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -349,7 +349,15 @@ void InterpreterImpl::initializeData(const Node& data) { if (HAS_ATTR(data, "expr")) { // expression given directly std::string value = ATTR(data, "expr"); - _dataModel.assign(ATTR(data, "id"), value); + try { + _dataModel.assign(ATTR(data, "id"), value); + } catch (Event e) { + LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; + /// test 277 + /// todo: if the identifier is invalid we'll raise to error events + receiveInternal(e); + _dataModel.assign(ATTR(data, "id"), "undefined"); + } return; } @@ -376,7 +384,14 @@ void InterpreterImpl::initializeData(const Node& data) { inputSource.setByteStream(ssPtr); Arabica::SAX2DOM::Parser parser; if(parser.parse(inputSource) && parser.getDocument()) { - _dataModel.assign(ATTR(data, "id"), parser.getDocument()); + try { + _dataModel.assign(ATTR(data, "id"), parser.getDocument()); + return; + } catch (Event e) { + LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; + receiveInternal(e); + _dataModel.assign(ATTR(data, "id"), "undefined"); + } return; } } else if (data.hasChildNodes()) { @@ -443,7 +458,7 @@ void InterpreterImpl::initializeData(const Node& data) { void InterpreterImpl::normalize(Arabica::DOM::Element& scxml) { // TODO: Resolve XML includes - + // make sure every state has an id and set isFirstEntry to true Arabica::XPath::NodeSet states = _xpath.evaluate("//" + _xpathPrefix + "state", _scxml).asNodeSet(); for (int i = 0; i < states.size(); i++) { @@ -507,6 +522,14 @@ void InterpreterImpl::receiveInternal(const Event& event) { _internalQueue.push_back(event); } +void InterpreterImpl::receive(const Event& event, bool toFront) { + std::cout << "receive: " << event.name << std::endl; + if (toFront) { + _externalQueue.push_front(event); + } else { + _externalQueue.push(event); + } +} void InterpreterImpl::internalDoneSend(const Arabica::DOM::Node& state) { if (!isState(state)) @@ -688,6 +711,8 @@ void InterpreterImpl::send(const Arabica::DOM::Node& element) { sendReq.sendid = ATTR(getParentState(element), "id") + "." + getUUID(); if (HAS_ATTR(element, "idlocation") && _dataModel) { _dataModel.assign(ATTR(element, "idlocation"), "'" + sendReq.sendid + "'"); + } else { + sendReq.hideSendId = true; } } } catch (Event e) { @@ -777,37 +802,30 @@ void InterpreterImpl::delayedSend(void* userdata, std::string eventName) { InterpreterImpl* INSTANCE = data->first; SendRequest sendReq = data->second; - if (sendReq.target.length() == 0) { - /** - * If neither the 'target' nor the 'targetexpr' attribute is specified, the - * SCXML Processor must add the event will be added to the external event - * queue of the sending session. - */ - INSTANCE->_externalQueue.push(sendReq); + /** + * If neither the 'type' nor the 'typeexpr' is defined, the SCXML Processor + * must assume the default value of http://www.w3.org/TR/scxml/#SCXMLEventProcessor + */ + if (sendReq.type.length() == 0) + sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + + IOProcessor ioProc = INSTANCE->getIOProcessor(sendReq.type); + if (ioProc) { + try { + ioProc.send(sendReq); + } catch(...) { + LOG(ERROR) << "Exception caught while sending event to ioprocessor " << sendReq.type; + } } else { /** - * If neither the 'type' nor the 'typeexpr' is defined, the SCXML Processor - * must assume the default value of http://www.w3.org/TR/scxml/#SCXMLEventProcessor + * If the SCXML Processor does not support the type that is specified, it + * must place the event error.execution on the internal event queue. */ - if (sendReq.type.length() == 0) - sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; - IOProcessor ioProc = INSTANCE->getIOProcessor(sendReq.type); - if (ioProc) { - try { - ioProc.send(sendReq); - } catch(...) { - LOG(ERROR) << "Exception caught while sending event to ioprocessor " << sendReq.type; - } - } else { - /** - * If the SCXML Processor does not support the type that is specified, it - * must place the event error.execution on the internal event queue. - */ - Event exceptionEvent("error.execution", Event::PLATFORM); + Event exceptionEvent("error.execution", Event::PLATFORM); // exceptionEvent.sendid = sendReq.sendid; - INSTANCE->receiveInternal(exceptionEvent); - } + INSTANCE->receiveInternal(exceptionEvent); } + assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end()); INSTANCE->_sendIds.erase(sendReq.sendid); } @@ -1246,6 +1264,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node& cont } void InterpreterImpl::returnDoneEvent(const Arabica::DOM::Node& state) { + std::cout << state << std::endl; if (_parentQueue != NULL) { Event done; done.name = "done.invoke." + _sessionId; diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 9be85ff..2a63604 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -66,9 +66,9 @@ public: }; enum Capabilities { - CAN_NOTHING = 0, - CAN_BASIC_HTTP = 1, - CAN_GENERIC_HTTP = 2, + CAN_NOTHING = 0, + CAN_BASIC_HTTP = 1, + CAN_GENERIC_HTTP = 2, }; class InterpreterImpl : public boost::enable_shared_from_this { @@ -139,14 +139,8 @@ public: return ""; } - void inline receiveInternal(const Event& event); - void receive(const Event& event, bool toFront = false) { - if (toFront) { - _externalQueue.push_front(event); - } else { - _externalQueue.push(event); - } - } + void receiveInternal(const Event& event); + void receive(const Event& event, bool toFront = false); Event getCurrentEvent() { return _currEvent; @@ -553,7 +547,7 @@ public: boost::shared_ptr getImpl() { return _impl; } - + static std::map > getInstances() { tthread::lock_guard lock(_instanceMutex); std::map >::iterator instIter = _instances.begin(); @@ -566,9 +560,9 @@ public: } return _instances; } - + #endif - + protected: boost::shared_ptr _impl; static std::map > _instances; diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 72a2a99..9f5e8e2 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -94,9 +94,9 @@ public: PLATFORM = 3 }; - Event() : type(INTERNAL) {} - Event(const std::string& name, Type type = INTERNAL) : name(name), type(type) {} - Event(const Arabica::DOM::Node& xmlString) : type(INTERNAL) {}; + Event() : type(INTERNAL), hideSendId(false) {} + Event(const std::string& name, Type type = INTERNAL) : name(name), type(type), hideSendId(false) {} + Event(const Arabica::DOM::Node& xmlString) : type(INTERNAL), hideSendId(false) {}; bool operator< (const Event& other) const { return this < &other; } @@ -229,6 +229,7 @@ protected: std::string origintype; Arabica::DOM::Document dom; std::string sendid; + bool hideSendId; std::string invokeid; Data data; std::string content; diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index 3c97805..3c4a699 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -63,8 +63,9 @@ void InterpreterDraft6::interpret() { // executeGlobalScriptElements NodeSet globalScriptElems = filterChildElements(_xmlNSPrefix + "script", _scxml); for (unsigned int i = 0; i < globalScriptElems.size(); i++) { - if (_dataModel) + if (_dataModel) { executeContent(globalScriptElems[i]); + } } NodeSet initialTransitions; diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index e653607..fff3f9b 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -143,11 +143,13 @@ void V8DataModel::setEvent(const Event& event) { privData->dom = _dom; eventObj->SetInternalField(0, Arabica::DOM::V8DOM::toExternal(privData)); eventObj.MakeWeak(0, Arabica::DOM::V8SCXMLEvent::jsDestructor); + if (event.dom) { eventObj->Set(v8::String::New("data"), getDocumentAsValue(event.dom)); } else if (event.content.length() > 0) { // _event.data is a string eventObj->Set(v8::String::New("data"), v8::String::New(event.content.c_str())); +// eventObj->Set(v8::String::New("data"), v8::Undefined()); } else { // _event.data is KVP Event eventCopy(event); @@ -168,10 +170,11 @@ void V8DataModel::setEvent(const Event& event) { if (eventCopy.data.compound.size() > 0) { eventObj->Set(v8::String::New("data"), getDataAsValue(eventCopy.data)); // set data part of _event } else { - // test 343 + // test 343 / test 488 eventObj->Set(v8::String::New("data"), v8::Undefined()); // set data part of _event } } + // we cannot make _event v8::ReadOnly as it will ignore subsequent setEvents global->Set(v8::String::New("_event"), eventObj); } diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp index fec2a94..86fcfef 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.cpp @@ -18,6 +18,8 @@ v8::Handle V8SCXMLEvent::originAttrGetter(v8::Local prope v8::Local self = info.Holder(); struct V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); + if (privData->nativeObj->origin.length() == 0) + return v8::Undefined(); return v8::String::New(privData->nativeObj->origin.c_str()); } @@ -25,6 +27,8 @@ v8::Handle V8SCXMLEvent::origintypeAttrGetter(v8::Local p v8::Local self = info.Holder(); struct V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); + if (privData->nativeObj->origintype.length() == 0) + return v8::Undefined(); return v8::String::New(privData->nativeObj->origintype.c_str()); } @@ -48,17 +52,12 @@ v8::Handle V8SCXMLEvent::domAttrGetter(v8::Local property } -v8::Handle V8SCXMLEvent::sendidAttrGetter(v8::Local property, const v8::AccessorInfo& info) { - v8::Local self = info.Holder(); - struct V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); - - return v8::String::New(privData->nativeObj->sendid.c_str()); -} - v8::Handle V8SCXMLEvent::invokeidAttrGetter(v8::Local property, const v8::AccessorInfo& info) { v8::Local self = info.Holder(); struct V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); + if (privData->nativeObj->invokeid.length() == 0) + return v8::Undefined(); return v8::String::New(privData->nativeObj->invokeid.c_str()); } bool V8SCXMLEvent::hasInstance(v8::Handle value) { diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h index f17856a..e7dbacc 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h @@ -46,7 +46,7 @@ public: static v8::Handle originAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle origintypeAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle domAttrGetter(v8::Local property, const v8::AccessorInfo& info); - static v8::Handle sendidAttrGetter(v8::Local property, const v8::AccessorInfo& info); + static v8::Handle sendidCustomAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Handle invokeidAttrGetter(v8::Local property, const v8::AccessorInfo& info); static v8::Persistent Tmpl; @@ -72,7 +72,7 @@ public: v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); instance->SetAccessor(v8::String::NewSymbol("dom"), V8SCXMLEvent::domAttrGetter, 0, v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); - instance->SetAccessor(v8::String::NewSymbol("sendid"), V8SCXMLEvent::sendidAttrGetter, 0, + instance->SetAccessor(v8::String::NewSymbol("sendid"), V8SCXMLEvent::sendidCustomAttrGetter, 0, v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); instance->SetAccessor(v8::String::NewSymbol("invokeid"), V8SCXMLEvent::invokeidAttrGetter, 0, v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp index 05644b0..4eecb94 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp @@ -5,7 +5,7 @@ namespace DOM { v8::Handle V8SCXMLEvent::typeCustomAttrGetter(v8::Local property, const v8::AccessorInfo& info) { v8::Local self = info.Holder(); - V8SCXMLEvent::V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); + V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); switch (privData->nativeObj->type) { case uscxml::Event::INTERNAL: @@ -23,5 +23,14 @@ v8::Handle V8SCXMLEvent::typeCustomAttrGetter(v8::Local p return v8::String::New("unknown"); } +v8::Handle V8SCXMLEvent::sendidCustomAttrGetter(v8::Local property, const v8::AccessorInfo& info) { + v8::Local self = info.Holder(); + V8SCXMLEventPrivate* privData = V8DOM::toClassPtr(self->GetInternalField(0)); + + if (privData->nativeObj->sendid.length() == 0 || privData->nativeObj->hideSendId) + return v8::Undefined(); + return v8::String::New(privData->nativeObj->sendid.c_str()); +} + } } \ No newline at end of file diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp index 9ae62a8..7564f1d 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp @@ -120,7 +120,7 @@ void BasicHTTPIOProcessor::send(const SendRequest& req) { bool isLocal = false; std::string target; - if (req.target.length() > 0) { + if (req.target.length() > 0 && !boost::equals(req.target, _url)) { target = req.target; } else { isLocal = true; diff --git a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp index 3dabafe..288bfb7 100644 --- a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp @@ -71,10 +71,21 @@ void SCXMLIOProcessor::send(const SendRequest& req) { SendRequest reqCopy(req); // test 253 - reqCopy.origintype = "scxml"; + reqCopy.origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; reqCopy.origin = _url; if (false) { + } else if(reqCopy.target.length() == 0) { + /** + * If neither the 'target' nor the 'targetexpr' attribute is specified, the + * SCXML Processor must add the event will be added to the external event + * queue of the sending session. + */ + + // test333 vs test351 +// reqCopy.sendid = ""; + // test 198 + _interpreter->receive(reqCopy); } else if (boost::iequals(reqCopy.target, "#_internal")) { /** * #_internal: If the target is the special term '#_internal', the Processor @@ -97,10 +108,10 @@ void SCXMLIOProcessor::send(const SendRequest& req) { other->receive(reqCopy); } else { LOG(ERROR) << "Can not send to scxml session " << sessionId << " - not known" << std::endl; - _interpreter->receiveInternal(Event("error.communication", Event::PLATFORM)); + Event error("error.communication", Event::PLATFORM); + error.sendid = reqCopy.sendid; + _interpreter->receiveInternal(error); } - - } else if (boost::iequals(reqCopy.target, "#_parent")) { /** * #_parent: If the target is the special term '#_parent', the Processor must @@ -111,9 +122,11 @@ void SCXMLIOProcessor::send(const SendRequest& req) { _interpreter->_parentQueue->push(reqCopy); } else { LOG(ERROR) << "Can not send to parent, we were not invoked" << std::endl; - _interpreter->receiveInternal(Event("error.communication", Event::PLATFORM)); + Event error("error.communication", Event::PLATFORM); + error.sendid = reqCopy.sendid; + _interpreter->receiveInternal(error); } - } else if (boost::starts_with(reqCopy.target, "#_") == 0) { + } else if (boost::starts_with(reqCopy.target, "#_")) { /** * #_invokeid: If the target is the special term '#_invokeid', where invokeid * is the invokeid of an SCXML session that the sending session has created @@ -130,9 +143,20 @@ void SCXMLIOProcessor::send(const SendRequest& req) { } } else { LOG(ERROR) << "Can not send to invoked component '" << invokeId << "', no such invokeId" << std::endl; - _interpreter->receiveInternal(Event("error.communication", Event::PLATFORM)); + Event error("error.communication", Event::PLATFORM); + error.sendid = reqCopy.sendid; + _interpreter->receiveInternal(error); } } else { + URL target(reqCopy.target); + if (target.isAbsolute()) { + BasicHTTPIOProcessor::send(reqCopy); + } else { + LOG(ERROR) << "Not sure what to make of the target '" << reqCopy.target << "' - raising error" << std::endl; + Event error("error.execution", Event::PLATFORM); + error.sendid = reqCopy.sendid; + _interpreter->receiveInternal(error); + } } } diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp index 70c8b80..3b6c43a 100644 --- a/test/src/test-w3c.cpp +++ b/test/src/test-w3c.cpp @@ -96,8 +96,8 @@ void printUsageAndExit() { } class W3CStatusMonitor : public uscxml::InterpreterMonitor { - void beforeCompletion(uscxml::InterpreterImpl* interpreter) { - Arabica::XPath::NodeSet config = interpreter->getConfiguration(); + void beforeCompletion(uscxml::Interpreter interpreter) { + Arabica::XPath::NodeSet config = interpreter.getConfiguration(); if (config.size() == 1 && boost::iequals(ATTR(config[0], "id"), "pass")) exit(EXIT_SUCCESS); exit(EXIT_FAILURE); -- cgit v0.12