def test_loads_and_dumps_with_not_all_params(self): question = 'What is your name?' toml_string = f''' [[action]] type = "ask" question = "{question}" ''' sc = Shortcut.loads(toml_string) assert len(sc.actions) == 1 action = sc.actions[0] assert action.keyword == 'ask' assert action.data['question'] == question assert action.itype == 'is.workflow.actions.ask' assert action.data == {'question': question} dump = sc.dumps() exp_dump = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>WFWorkflowActions</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.ask</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>WFAskActionPrompt</key>\n\t\t\t\t<string>What is your name?</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>WFWorkflowClientRelease</key>\n\t<string>2.0</string>\n\t<key>WFWorkflowClientVersion</key>\n\t<string>700</string>\n\t<key>WFWorkflowIcon</key>\n\t<dict>\n\t\t<key>WFWorkflowIconGlyphNumber</key>\n\t\t<integer>59511</integer>\n\t\t<key>WFWorkflowIconImageData</key>\n\t\t<data>\n\t\t</data>\n\t\t<key>WFWorkflowIconStartColor</key>\n\t\t<integer>431817727</integer>\n\t</dict>\n\t<key>WFWorkflowImportQuestions</key>\n\t<array/>\n\t<key>WFWorkflowInputContentItemClasses</key>\n\t<array>\n\t\t<string>WFAppStoreAppContentItem</string>\n\t\t<string>WFArticleContentItem</string>\n\t\t<string>WFContactContentItem</string>\n\t\t<string>WFDateContentItem</string>\n\t\t<string>WFEmailAddressContentItem</string>\n\t\t<string>WFGenericFileContentItem</string>\n\t\t<string>WFImageContentItem</string>\n\t\t<string>WFiTunesProductContentItem</string>\n\t\t<string>WFLocationContentItem</string>\n\t\t<string>WFDCMapsLinkContentItem</string>\n\t\t<string>WFAVAssetContentItem</string>\n\t\t<string>WFPDFContentItem</string>\n\t\t<string>WFPhoneNumberContentItem</string>\n\t\t<string>WFRichTextContentItem</string>\n\t\t<string>WFSafariWebPageContentItem</string>\n\t\t<string>WFStringContentItem</string>\n\t\t<string>WFURLContentItem</string>\n\t</array>\n\t<key>WFWorkflowTypes</key>\n\t<array>\n\t\t<string>NCWidget</string>\n\t\t<string>WatchKit</string>\n\t</array>\n</dict>\n</plist>\n' assert dump == exp_dump
def test_dumps_to_plist(self): sc = Shortcut.loads(self.toml_string) dump = sc.dumps(file_format=FMT_SHORTCUT) exp_dump = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>WFWorkflowActions</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.downloadurl</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>Advanced</key>\n\t\t\t\t<true/>\n\t\t\t\t<key>ShowHeaders</key>\n\t\t\t\t<true/>\n\t\t\t\t<key>WFHTTPBodyType</key>\n\t\t\t\t<string>Json</string>\n\t\t\t\t<key>WFHTTPHeaders</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>WFDictionaryFieldValueItems</key>\n\t\t\t\t\t\t<array>\n\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t<key>WFItemType</key>\n\t\t\t\t\t\t\t\t<integer>0</integer>\n\t\t\t\t\t\t\t\t<key>WFKey</key>\n\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t\t\t\t\t<string>header1</string>\n\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t<key>WFValue</key>\n\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t\t\t\t\t<string>value</string>\n\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t<key>WFItemType</key>\n\t\t\t\t\t\t\t\t<integer>0</integer>\n\t\t\t\t\t\t\t\t<key>WFKey</key>\n\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t\t\t\t\t<string>authorization</string>\n\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t<key>WFValue</key>\n\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t\t<key>{0, 1}</key>\n\t\t\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t\t\t<key>Type</key>\n\t\t\t\t\t\t\t\t\t\t\t\t<string>Variable</string>\n\t\t\t\t\t\t\t\t\t\t\t\t<key>VariableName</key>\n\t\t\t\t\t\t\t\t\t\t\t\t<string>authorization</string>\n\t\t\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t\t\t\t\t<string></string>\n\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t</array>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t<string>WFDictionaryFieldValue</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>WFHTTPMethod</key>\n\t\t\t\t<string>POST</string>\n\t\t\t\t<key>WFJSONValues</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>WFDictionaryFieldValueItems</key>\n\t\t\t\t\t\t<array>\n\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t<key>WFItemType</key>\n\t\t\t\t\t\t\t\t<integer>0</integer>\n\t\t\t\t\t\t\t\t<key>WFKey</key>\n\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t\t\t\t\t<string>k</string>\n\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t<key>WFValue</key>\n\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t\t\t\t\t<dict>\n\t\t\t\t\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t\t\t\t\t<string>v</string>\n\t\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t\t</dict>\n\t\t\t\t\t\t</array>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t<string>WFDictionaryFieldValue</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>WFWorkflowClientRelease</key>\n\t<string>2.0</string>\n\t<key>WFWorkflowClientVersion</key>\n\t<string>700</string>\n\t<key>WFWorkflowIcon</key>\n\t<dict>\n\t\t<key>WFWorkflowIconGlyphNumber</key>\n\t\t<integer>59511</integer>\n\t\t<key>WFWorkflowIconImageData</key>\n\t\t<data>\n\t\t</data>\n\t\t<key>WFWorkflowIconStartColor</key>\n\t\t<integer>431817727</integer>\n\t</dict>\n\t<key>WFWorkflowImportQuestions</key>\n\t<array/>\n\t<key>WFWorkflowInputContentItemClasses</key>\n\t<array>\n\t\t<string>WFAppStoreAppContentItem</string>\n\t\t<string>WFArticleContentItem</string>\n\t\t<string>WFContactContentItem</string>\n\t\t<string>WFDateContentItem</string>\n\t\t<string>WFEmailAddressContentItem</string>\n\t\t<string>WFGenericFileContentItem</string>\n\t\t<string>WFImageContentItem</string>\n\t\t<string>WFiTunesProductContentItem</string>\n\t\t<string>WFLocationContentItem</string>\n\t\t<string>WFDCMapsLinkContentItem</string>\n\t\t<string>WFAVAssetContentItem</string>\n\t\t<string>WFPDFContentItem</string>\n\t\t<string>WFPhoneNumberContentItem</string>\n\t\t<string>WFRichTextContentItem</string>\n\t\t<string>WFSafariWebPageContentItem</string>\n\t\t<string>WFStringContentItem</string>\n\t\t<string>WFURLContentItem</string>\n\t</array>\n\t<key>WFWorkflowTypes</key>\n\t<array>\n\t\t<string>NCWidget</string>\n\t\t<string>WatchKit</string>\n\t</array>\n</dict>\n</plist>\n' assert dump == exp_dump
def test_loads(self): toml_string = ''' [[action]] type = "text" text = "ping" [[action]] type = "set_variable" name = "variable" [[action]] type = "show_result" text = "My variable: {{variable}}" ''' sc = Shortcut.loads(toml_string) assert len(sc.actions) == 3 assert sc.actions[0].keyword == 'text' assert sc.actions[0].data['text'] == 'ping' assert sc.actions[0].itype == 'is.workflow.actions.gettext' assert sc.actions[1].keyword == 'set_variable' assert sc.actions[1].data['name'] == 'variable' assert sc.actions[1].itype == 'is.workflow.actions.setvariable' assert sc.actions[2].keyword == 'show_result' assert sc.actions[2].data['text'] == 'My variable: {{variable}}' assert sc.actions[2].itype == 'is.workflow.actions.showresult'
def test_loads_plist(self): plist = '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>WFWorkflowActions</key> <array> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.urlencode</string> <key>WFWorkflowActionParameters</key> <dict> <key>WFEncodeMode</key> <string>Decode</string> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.urlencode</string> <key>WFWorkflowActionParameters</key> <dict> <key>WFEncodeMode</key> <string>Encode</string> </dict> </dict> </array> <key>WFWorkflowClientRelease</key> <string>2.0</string> <key>WFWorkflowClientVersion</key> <string>700</string> <key>WFWorkflowIcon</key> <dict> <key>WFWorkflowIconGlyphNumber</key> <integer>59511</integer> <key>WFWorkflowIconImageData</key> <data> </data> <key>WFWorkflowIconStartColor</key> <integer>4271458815</integer> </dict> <key>WFWorkflowImportQuestions</key> <array/> <key>WFWorkflowInputContentItemClasses</key> <array> <string>WFAppStoreAppContentItem</string> <string>WFArticleContentItem</string> <string>WFContactContentItem</string> <string>WFDateContentItem</string> <string>WFEmailAddressContentItem</string> <string>WFGenericFileContentItem</string> <string>WFImageContentItem</string> <string>WFiTunesProductContentItem</string> <string>WFLocationContentItem</string> <string>WFDCMapsLinkContentItem</string> <string>WFAVAssetContentItem</string> <string>WFPDFContentItem</string> <string>WFPhoneNumberContentItem</string> <string>WFRichTextContentItem</string> <string>WFSafariWebPageContentItem</string> <string>WFStringContentItem</string> <string>WFURLContentItem</string> </array> <key>WFWorkflowTypes</key> <array> <string>NCWidget</string> <string>WatchKit</string> </array> </dict> </plist>' sc = Shortcut.loads(plist, file_format=FMT_SHORTCUT) assert isinstance(sc.actions[0], URLDecodeAction) is True assert isinstance(sc.actions[1], URLEncodeAction) is True
def test_loads_from_toml(self): sc = Shortcut.loads(self.toml_string) assert len(sc.actions) == 1 action = sc.actions[0] assert isinstance(action, GetURLAction) is True exp_data = { 'headers': [ { 'key': 'header1', 'value': 'value' }, { 'key': 'authorization', 'value': '{{authorization}}' }, ], 'json': [ { 'key': 'k', 'value': 'v' }, ], 'advanced': True, 'method': 'POST', } assert action.data == exp_data
def test_loads_from_toml(self): sc = Shortcut.loads(self.toml_string) assert len(sc.actions) == 2 assert isinstance(sc.actions[0], RepeatEachStartAction) is True assert isinstance(sc.actions[1], RepeatEachEndAction) is True
def test_ifelse_loads_from_plist(self): plist = '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>WFWorkflowActions</key> <array> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.conditional</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>37E06FDE-DD29-4981-99C1-7765BF56E89E</string> <key>WFConditionalActionString</key> <string>123</string> <key>WFControlFlowMode</key> <integer>0</integer> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.conditional</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>37E06FDE-DD29-4981-99C1-7765BF56E89E</string> <key>WFControlFlowMode</key> <integer>1</integer> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.conditional</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>37E06FDE-DD29-4981-99C1-7765BF56E89E</string> <key>WFControlFlowMode</key> <integer>2</integer> </dict> </dict> </array> <key>WFWorkflowClientRelease</key> <string>2.0</string> <key>WFWorkflowClientVersion</key> <string>700</string> <key>WFWorkflowIcon</key> <dict> <key>WFWorkflowIconGlyphNumber</key> <integer>59511</integer> <key>WFWorkflowIconImageData</key> <data> </data> <key>WFWorkflowIconStartColor</key> <integer>3679049983</integer> </dict> <key>WFWorkflowImportQuestions</key> <array/> <key>WFWorkflowInputContentItemClasses</key> <array> <string>WFAppStoreAppContentItem</string> <string>WFArticleContentItem</string> <string>WFContactContentItem</string> <string>WFDateContentItem</string> <string>WFEmailAddressContentItem</string> <string>WFGenericFileContentItem</string> <string>WFImageContentItem</string> <string>WFiTunesProductContentItem</string> <string>WFLocationContentItem</string> <string>WFDCMapsLinkContentItem</string> <string>WFAVAssetContentItem</string> <string>WFPDFContentItem</string> <string>WFPhoneNumberContentItem</string> <string>WFRichTextContentItem</string> <string>WFSafariWebPageContentItem</string> <string>WFStringContentItem</string> <string>WFURLContentItem</string> </array> <key>WFWorkflowTypes</key> <array> <string>NCWidget</string> <string>WatchKit</string> </array> </dict> </plist>' sc = Shortcut.loads(plist, file_format=FMT_SHORTCUT) assert isinstance(sc.actions[0], actions.IfAction) is True assert isinstance(sc.actions[1], actions.ElseAction) is True assert isinstance(sc.actions[2], actions.EndIfAction) is True
def _assert_toml_loads(self, toml, exp_cls, exp_data): sc = Shortcut.loads(toml) assert len(sc.actions) == 1 action = sc.actions[0] assert isinstance(sc.actions[0], exp_cls) is True assert action.data == exp_data
def test_repeat_loads_from_plist(self): plist = '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>WFWorkflowActions</key> <array> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.repeat.count</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>3AB1AA08-5518-4D74-B4D2-5766E30EC763</string> <key>WFControlFlowMode</key> <integer>0</integer> <key>WFRepeatCount</key> <real>2</real> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.repeat.count</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>3AB1AA08-5518-4D74-B4D2-5766E30EC763</string> <key>WFControlFlowMode</key> <integer>2</integer> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.repeat.each</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>7AAA3B89-3A5A-4C31-9675-5478E7F98059</string> <key>WFControlFlowMode</key> <integer>0</integer> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.repeat.each</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>7AAA3B89-3A5A-4C31-9675-5478E7F98059</string> <key>WFControlFlowMode</key> <integer>2</integer> </dict> </dict> </array> <key>WFWorkflowClientRelease</key> <string>2.0</string> <key>WFWorkflowClientVersion</key> <string>700</string> <key>WFWorkflowIcon</key> <dict> <key>WFWorkflowIconGlyphNumber</key> <integer>59511</integer> <key>WFWorkflowIconImageData</key> <data> </data> <key>WFWorkflowIconStartColor</key> <integer>3679049983</integer> </dict> <key>WFWorkflowImportQuestions</key> <array/> <key>WFWorkflowInputContentItemClasses</key> <array> <string>WFAppStoreAppContentItem</string> <string>WFArticleContentItem</string> <string>WFContactContentItem</string> <string>WFDateContentItem</string> <string>WFEmailAddressContentItem</string> <string>WFGenericFileContentItem</string> <string>WFImageContentItem</string> <string>WFiTunesProductContentItem</string> <string>WFLocationContentItem</string> <string>WFDCMapsLinkContentItem</string> <string>WFAVAssetContentItem</string> <string>WFPDFContentItem</string> <string>WFPhoneNumberContentItem</string> <string>WFRichTextContentItem</string> <string>WFSafariWebPageContentItem</string> <string>WFStringContentItem</string> <string>WFURLContentItem</string> </array> <key>WFWorkflowTypes</key> <array> <string>NCWidget</string> <string>WatchKit</string> </array> </dict> </plist>' sc = Shortcut.loads(plist, file_format=FMT_SHORTCUT) assert isinstance(sc.actions[0], actions.RepeatStartAction) is True assert isinstance(sc.actions[1], actions.RepeatEndAction) is True assert isinstance(sc.actions[2], actions.RepeatEachStartAction) is True assert isinstance(sc.actions[3], actions.RepeatEachEndAction) is True
def test_loads_from_plist(self): plist = '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>WFWorkflowActions</key> <array> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.choosefrommenu</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>76C3AEC3-29EF-4FC8-9744-1CF34D07CA54</string> <key>WFControlFlowMode</key> <integer>0</integer> <key>WFMenuItems</key> <array> <string>F</string> <string>S</string> <string>T</string> </array> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.choosefrommenu</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>76C3AEC3-29EF-4FC8-9744-1CF34D07CA54</string> <key>WFControlFlowMode</key> <integer>1</integer> <key>WFMenuItemTitle</key> <string>F</string> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.choosefrommenu</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>76C3AEC3-29EF-4FC8-9744-1CF34D07CA54</string> <key>WFControlFlowMode</key> <integer>1</integer> <key>WFMenuItemTitle</key> <string>S</string> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.choosefrommenu</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>76C3AEC3-29EF-4FC8-9744-1CF34D07CA54</string> <key>WFControlFlowMode</key> <integer>1</integer> <key>WFMenuItemTitle</key> <string>T</string> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.choosefrommenu</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>76C3AEC3-29EF-4FC8-9744-1CF34D07CA54</string> <key>WFControlFlowMode</key> <integer>2</integer> </dict> </dict> </array> <key>WFWorkflowClientRelease</key> <string>2.0</string> <key>WFWorkflowClientVersion</key> <string>700</string> <key>WFWorkflowIcon</key> <dict> <key>WFWorkflowIconGlyphNumber</key> <integer>59511</integer> <key>WFWorkflowIconImageData</key> <data> </data> <key>WFWorkflowIconStartColor</key> <integer>3679049983</integer> </dict> <key>WFWorkflowImportQuestions</key> <array/> <key>WFWorkflowInputContentItemClasses</key> <array> <string>WFAppStoreAppContentItem</string> <string>WFArticleContentItem</string> <string>WFContactContentItem</string> <string>WFDateContentItem</string> <string>WFEmailAddressContentItem</string> <string>WFGenericFileContentItem</string> <string>WFImageContentItem</string> <string>WFiTunesProductContentItem</string> <string>WFLocationContentItem</string> <string>WFDCMapsLinkContentItem</string> <string>WFAVAssetContentItem</string> <string>WFPDFContentItem</string> <string>WFPhoneNumberContentItem</string> <string>WFRichTextContentItem</string> <string>WFSafariWebPageContentItem</string> <string>WFStringContentItem</string> <string>WFURLContentItem</string> </array> <key>WFWorkflowTypes</key> <array> <string>NCWidget</string> <string>WatchKit</string> </array> </dict> </plist>' sc = Shortcut.loads(plist, file_format=FMT_SHORTCUT) assert isinstance(sc.actions[0], actions.MenuStartAction) is True assert isinstance(sc.actions[1], actions.MenuItemAction) is True assert isinstance(sc.actions[2], actions.MenuItemAction) is True assert isinstance(sc.actions[3], actions.MenuItemAction) is True assert isinstance(sc.actions[4], actions.MenuEndAction) is True
def test_dumps_to_plist(self): sc = Shortcut.loads(self.toml_string) mocked_uuid = mock.Mock() mocked_uuid.uuid4.return_value = 'some-uuid' with mock.patch('shortcuts.shortcut.uuid', mocked_uuid): dump = sc.dumps(file_format=FMT_SHORTCUT) exp_dump = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>WFWorkflowActions</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.repeat.each</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>some-uuid</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>0</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.repeat.each</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>some-uuid</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>WFWorkflowClientRelease</key>\n\t<string>2.0</string>\n\t<key>WFWorkflowClientVersion</key>\n\t<string>700</string>\n\t<key>WFWorkflowIcon</key>\n\t<dict>\n\t\t<key>WFWorkflowIconGlyphNumber</key>\n\t\t<integer>59511</integer>\n\t\t<key>WFWorkflowIconImageData</key>\n\t\t<data>\n\t\t</data>\n\t\t<key>WFWorkflowIconStartColor</key>\n\t\t<integer>431817727</integer>\n\t</dict>\n\t<key>WFWorkflowImportQuestions</key>\n\t<array/>\n\t<key>WFWorkflowInputContentItemClasses</key>\n\t<array>\n\t\t<string>WFAppStoreAppContentItem</string>\n\t\t<string>WFArticleContentItem</string>\n\t\t<string>WFContactContentItem</string>\n\t\t<string>WFDateContentItem</string>\n\t\t<string>WFEmailAddressContentItem</string>\n\t\t<string>WFGenericFileContentItem</string>\n\t\t<string>WFImageContentItem</string>\n\t\t<string>WFiTunesProductContentItem</string>\n\t\t<string>WFLocationContentItem</string>\n\t\t<string>WFDCMapsLinkContentItem</string>\n\t\t<string>WFAVAssetContentItem</string>\n\t\t<string>WFPDFContentItem</string>\n\t\t<string>WFPhoneNumberContentItem</string>\n\t\t<string>WFRichTextContentItem</string>\n\t\t<string>WFSafariWebPageContentItem</string>\n\t\t<string>WFStringContentItem</string>\n\t\t<string>WFURLContentItem</string>\n\t</array>\n\t<key>WFWorkflowTypes</key>\n\t<array>\n\t\t<string>NCWidget</string>\n\t\t<string>WatchKit</string>\n\t</array>\n</dict>\n</plist>\n' assert dump == exp_dump
def test_loads_from_toml(self): sc = Shortcut.loads(self.toml_string) assert len(sc.actions) == 3 if_action = sc.actions[0] else_action = sc.actions[1] endif_action = sc.actions[2] assert if_action.data == {'compare_with': 'true', 'condition': 'equals', 'group_id': '123'} assert else_action.data == {'group_id': '123'} assert endif_action.data == {'group_id': '123'}
def test_loads_plist(self): plist = SHORTCUT_EMPTY_PLIST_TEMPLATE.format( actions=self.action_xml.strip()) plist = plist.replace(' ', '').replace('\n', '') # remove all indentation sc = Shortcut.loads(plist, file_format=FMT_SHORTCUT) assert len(sc.actions) == 1 assert isinstance(sc.actions[0], self.action_class) is True exp_params = self.exp_xml_params if self.exp_xml_params else {} assert sc.actions[0].data == exp_params
def test_loads_from_toml(self): sc = Shortcut.loads(self.toml_string) assert len(sc.actions) == 1 action = sc.actions[0] assert isinstance(action, GetVariableAction) is True exp_data = { 'name': 'var', } assert action.data == exp_data
def test_loads_from_plist(self): plist = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>WFWorkflowActions</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.getvariable</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>WFVariable</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>Type</key>\n\t\t\t\t\t\t<string>Variable</string>\n\t\t\t\t\t\t<key>VariableName</key>\n\t\t\t\t\t\t<string>var</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t<string>WFTextTokenAttachment</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>WFWorkflowClientRelease</key>\n\t<string>2.0</string>\n\t<key>WFWorkflowClientVersion</key>\n\t<string>700</string>\n\t<key>WFWorkflowIcon</key>\n\t<dict>\n\t\t<key>WFWorkflowIconGlyphNumber</key>\n\t\t<integer>59511</integer>\n\t\t<key>WFWorkflowIconImageData</key>\n\t\t<data>\n\t\t</data>\n\t\t<key>WFWorkflowIconStartColor</key>\n\t\t<integer>431817727</integer>\n\t</dict>\n\t<key>WFWorkflowImportQuestions</key>\n\t<array/>\n\t<key>WFWorkflowInputContentItemClasses</key>\n\t<array>\n\t\t<string>WFAppStoreAppContentItem</string>\n\t\t<string>WFArticleContentItem</string>\n\t\t<string>WFContactContentItem</string>\n\t\t<string>WFDateContentItem</string>\n\t\t<string>WFEmailAddressContentItem</string>\n\t\t<string>WFGenericFileContentItem</string>\n\t\t<string>WFImageContentItem</string>\n\t\t<string>WFiTunesProductContentItem</string>\n\t\t<string>WFLocationContentItem</string>\n\t\t<string>WFDCMapsLinkContentItem</string>\n\t\t<string>WFAVAssetContentItem</string>\n\t\t<string>WFPDFContentItem</string>\n\t\t<string>WFPhoneNumberContentItem</string>\n\t\t<string>WFRichTextContentItem</string>\n\t\t<string>WFSafariWebPageContentItem</string>\n\t\t<string>WFStringContentItem</string>\n\t\t<string>WFURLContentItem</string>\n\t</array>\n\t<key>WFWorkflowTypes</key>\n\t<array>\n\t\t<string>NCWidget</string>\n\t\t<string>WatchKit</string>\n\t</array>\n</dict>\n</plist>\n' sc = Shortcut.loads(plist, file_format='plist') assert len(sc.actions) == 1 action = sc.actions[0] assert isinstance(action, GetVariableAction) is True exp_data = { 'name': 'var', } assert action.data == exp_data
def test_loads_from_toml(self): sc = Shortcut.loads(self.toml_string) assert len(sc.actions) == 1 action = sc.actions[0] assert isinstance(action, DictionaryAction) is True exp_data = { 'items': [ {'key': 'some key', 'value': 'some value'}, {'key': 'another key', 'value': '{{x}}'}, ], } assert action.data == exp_data
def test_loads_plist(self): plist = '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>WFWorkflowActions</key> <array> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.gettext</string> <key>WFWorkflowActionParameters</key> <dict> <key>WFTextActionText</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>ping</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.setvariable</string> <key>WFWorkflowActionParameters</key> <dict> <key>WFVariableName</key> <string>init</string> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.conditional</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>73C63251-8CE2-4DC2-A078-57CBBC823657</string> <key>WFCondition</key> <string>Equals</string> <key>WFConditionalActionString</key> <string>ping</string> <key>WFControlFlowMode</key> <integer>0</integer> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.gettext</string> <key>WFWorkflowActionParameters</key> <dict> <key>WFTextActionText</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>test</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.setvariable</string> <key>WFWorkflowActionParameters</key> <dict> <key>WFVariableName</key> <string>test</string> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.conditional</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>73C63251-8CE2-4DC2-A078-57CBBC823657</string> <key>WFControlFlowMode</key> <integer>1</integer> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.vibrate</string> <key>WFWorkflowActionParameters</key> <dict/> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.downloadurl</string> <key>WFWorkflowActionParameters</key> <dict> <key>Advanced</key> <true/> <key>ShowHeaders</key> <true/> <key>WFHTTPBodyType</key> <string>Json</string> <key>WFHTTPHeaders</key> <dict> <key>Value</key> <dict> <key>WFDictionaryFieldValueItems</key> <array> <dict> <key>WFItemType</key> <integer>0</integer> <key>WFKey</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>Auth</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> <key>WFValue</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>token</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> </dict> </array> </dict> <key>WFSerializationType</key> <string>WFDictionaryFieldValue</string> </dict> <key>WFHTTPMethod</key> <string>POST</string> <key>WFJSONValues</key> <dict> <key>Value</key> <dict> <key>WFDictionaryFieldValueItems</key> <array> <dict> <key>WFItemType</key> <integer>0</integer> <key>WFKey</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>key1</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> <key>WFValue</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict> <key>{0, 1}</key> <dict> <key>Type</key> <string>Variable</string> <key>VariableName</key> <string>init</string> </dict> </dict> <key>string</key> <string></string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> </dict> <dict> <key>WFItemType</key> <integer>0</integer> <key>WFKey</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>key2</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> <key>WFValue</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>5</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> </dict> </array> </dict> <key>WFSerializationType</key> <string>WFDictionaryFieldValue</string> </dict> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.conditional</string> <key>WFWorkflowActionParameters</key> <dict> <key>GroupingIdentifier</key> <string>73C63251-8CE2-4DC2-A078-57CBBC823657</string> <key>WFControlFlowMode</key> <integer>2</integer> </dict> </dict> <dict> <key>WFWorkflowActionIdentifier</key> <string>is.workflow.actions.notification</string> <key>WFWorkflowActionParameters</key> <dict> <key>WFNotificationActionBody</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict> <key>{13, 1}</key> <dict> <key>Type</key> <string>Variable</string> <key>VariableName</key> <string>test</string> </dict> </dict> <key>string</key> <string>Hello World! </string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> <key>WFNotificationActionSound</key> <false/> <key>WFNotificationActionTitle</key> <dict> <key>Value</key> <dict> <key>attachmentsByRange</key> <dict/> <key>string</key> <string>hi</string> </dict> <key>WFSerializationType</key> <string>WFTextTokenString</string> </dict> </dict> </dict> </array> <key>WFWorkflowClientRelease</key> <string>2.0</string> <key>WFWorkflowClientVersion</key> <string>700</string> <key>WFWorkflowIcon</key> <dict> <key>WFWorkflowIconGlyphNumber</key> <integer>59511</integer> <key>WFWorkflowIconImageData</key> <data> </data> <key>WFWorkflowIconStartColor</key> <integer>431817727</integer> </dict> <key>WFWorkflowImportQuestions</key> <array/> <key>WFWorkflowInputContentItemClasses</key> <array> <string>WFAppStoreAppContentItem</string> <string>WFArticleContentItem</string> <string>WFContactContentItem</string> <string>WFDateContentItem</string> <string>WFEmailAddressContentItem</string> <string>WFGenericFileContentItem</string> <string>WFImageContentItem</string> <string>WFiTunesProductContentItem</string> <string>WFLocationContentItem</string> <string>WFDCMapsLinkContentItem</string> <string>WFAVAssetContentItem</string> <string>WFPDFContentItem</string> <string>WFPhoneNumberContentItem</string> <string>WFRichTextContentItem</string> <string>WFSafariWebPageContentItem</string> <string>WFStringContentItem</string> <string>WFURLContentItem</string> </array> <key>WFWorkflowTypes</key> <array> <string>NCWidget</string> <string>WatchKit</string> </array> </dict> </plist>' sc = Shortcut.loads(plist, file_format=FMT_SHORTCUT) exp_actions = [ TextAction, SetVariableAction, IfAction, TextAction, SetVariableAction, ElseAction, VibrateAction, GetURLAction, EndIfAction, NotificationAction, ] assert [type(a) for a in sc.actions] == exp_actions
def test_dumps_to_plist(self): sc = Shortcut.loads(self.toml_string) dump = sc.dumps(file_format=FMT_SHORTCUT) exp_dump = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>WFWorkflowActions</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.conditional</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>123</string>\n\t\t\t\t<key>WFCondition</key>\n\t\t\t\t<string>Equals</string>\n\t\t\t\t<key>WFConditionalActionString</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t<string>true</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>0</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.conditional</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>123</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.conditional</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>123</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>WFWorkflowClientRelease</key>\n\t<string>2.0</string>\n\t<key>WFWorkflowClientVersion</key>\n\t<string>700</string>\n\t<key>WFWorkflowIcon</key>\n\t<dict>\n\t\t<key>WFWorkflowIconGlyphNumber</key>\n\t\t<integer>59511</integer>\n\t\t<key>WFWorkflowIconImageData</key>\n\t\t<data>\n\t\t</data>\n\t\t<key>WFWorkflowIconStartColor</key>\n\t\t<integer>431817727</integer>\n\t</dict>\n\t<key>WFWorkflowImportQuestions</key>\n\t<array/>\n\t<key>WFWorkflowInputContentItemClasses</key>\n\t<array>\n\t\t<string>WFAppStoreAppContentItem</string>\n\t\t<string>WFArticleContentItem</string>\n\t\t<string>WFContactContentItem</string>\n\t\t<string>WFDateContentItem</string>\n\t\t<string>WFEmailAddressContentItem</string>\n\t\t<string>WFGenericFileContentItem</string>\n\t\t<string>WFImageContentItem</string>\n\t\t<string>WFiTunesProductContentItem</string>\n\t\t<string>WFLocationContentItem</string>\n\t\t<string>WFDCMapsLinkContentItem</string>\n\t\t<string>WFAVAssetContentItem</string>\n\t\t<string>WFPDFContentItem</string>\n\t\t<string>WFPhoneNumberContentItem</string>\n\t\t<string>WFRichTextContentItem</string>\n\t\t<string>WFSafariWebPageContentItem</string>\n\t\t<string>WFStringContentItem</string>\n\t\t<string>WFURLContentItem</string>\n\t</array>\n\t<key>WFWorkflowTypes</key>\n\t<array>\n\t\t<string>NCWidget</string>\n\t\t<string>WatchKit</string>\n\t</array>\n</dict>\n</plist>\n' assert dump == exp_dump
def test_complex_condition_with_auto_group_id(self): toml = '''[[action]] type = "repeat_start" count = 2 [[action]] type = "text" text = "test" [[action]] type = "if" condition = "equals" compare_with = "test" [[action]] type = "show_result" text = "true!" [[action]] type = "else" [[action]] type = "show_result" text = "false!" [[action]] type = "endif" [[action]] type = "repeat_end"''' sc = Shortcut.loads(toml) mocked_uuid = mock.Mock() ids = ['first_id', 'second_id'] def _return_id(): return ids.pop() mocked_uuid.uuid4 = _return_id with mock.patch('shortcuts.shortcut.uuid', mocked_uuid): dump = sc.dumps(file_format='plist') assert len(ids) == 0 exp_dump = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>WFWorkflowActions</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.repeat.count</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>second_id</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>0</integer>\n\t\t\t\t<key>WFRepeatCount</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.gettext</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>WFTextActionText</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t<string>test</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.conditional</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>first_id</string>\n\t\t\t\t<key>WFCondition</key>\n\t\t\t\t<string>Equals</string>\n\t\t\t\t<key>WFConditionalActionString</key>\n\t\t\t\t<string>test</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>0</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.showresult</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>Text</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t<string>true!</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.conditional</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>first_id</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.showresult</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>Text</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>Value</key>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>attachmentsByRange</key>\n\t\t\t\t\t\t<dict/>\n\t\t\t\t\t\t<key>string</key>\n\t\t\t\t\t\t<string>false!</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<key>WFSerializationType</key>\n\t\t\t\t\t<string>WFTextTokenString</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.conditional</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>first_id</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>WFWorkflowActionIdentifier</key>\n\t\t\t<string>is.workflow.actions.repeat.count</string>\n\t\t\t<key>WFWorkflowActionParameters</key>\n\t\t\t<dict>\n\t\t\t\t<key>GroupingIdentifier</key>\n\t\t\t\t<string>second_id</string>\n\t\t\t\t<key>WFControlFlowMode</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>WFWorkflowClientRelease</key>\n\t<string>2.0</string>\n\t<key>WFWorkflowClientVersion</key>\n\t<string>700</string>\n\t<key>WFWorkflowIcon</key>\n\t<dict>\n\t\t<key>WFWorkflowIconGlyphNumber</key>\n\t\t<integer>59511</integer>\n\t\t<key>WFWorkflowIconImageData</key>\n\t\t<data>\n\t\t</data>\n\t\t<key>WFWorkflowIconStartColor</key>\n\t\t<integer>431817727</integer>\n\t</dict>\n\t<key>WFWorkflowImportQuestions</key>\n\t<array/>\n\t<key>WFWorkflowInputContentItemClasses</key>\n\t<array>\n\t\t<string>WFAppStoreAppContentItem</string>\n\t\t<string>WFArticleContentItem</string>\n\t\t<string>WFContactContentItem</string>\n\t\t<string>WFDateContentItem</string>\n\t\t<string>WFEmailAddressContentItem</string>\n\t\t<string>WFGenericFileContentItem</string>\n\t\t<string>WFImageContentItem</string>\n\t\t<string>WFiTunesProductContentItem</string>\n\t\t<string>WFLocationContentItem</string>\n\t\t<string>WFDCMapsLinkContentItem</string>\n\t\t<string>WFAVAssetContentItem</string>\n\t\t<string>WFPDFContentItem</string>\n\t\t<string>WFPhoneNumberContentItem</string>\n\t\t<string>WFRichTextContentItem</string>\n\t\t<string>WFSafariWebPageContentItem</string>\n\t\t<string>WFStringContentItem</string>\n\t\t<string>WFURLContentItem</string>\n\t</array>\n\t<key>WFWorkflowTypes</key>\n\t<array>\n\t\t<string>NCWidget</string>\n\t\t<string>WatchKit</string>\n\t</array>\n</dict>\n</plist>\n' assert dump == exp_dump # check all actions now has group_id group_id_for_repeat = sc.actions[0].data.get('group_id') assert group_id_for_repeat is not None group_id_for_if = sc.actions[2].data.get('group_id') assert group_id_for_if is not None # and they are not equal assert group_id_for_if != group_id_for_repeat # check that classes are correct assert isinstance(sc.actions[0], actions.RepeatStartAction) assert isinstance(sc.actions[2], actions.IfAction) for action in sc.actions: if isinstance(action, (actions.RepeatEndAction, actions.RepeatStartAction)): assert action.data.get('group_id') == group_id_for_repeat elif isinstance(action, (actions.IfAction, actions.ElseAction, actions.EndIfAction)): assert action.data.get('group_id') == group_id_for_if