001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools.seleniumbuilder;
016    
017    import com.liferay.portal.freemarker.FreeMarkerUtil;
018    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
019    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
020    import com.liferay.portal.kernel.util.ArrayUtil;
021    import com.liferay.portal.kernel.util.CharPool;
022    import com.liferay.portal.kernel.util.FileUtil;
023    import com.liferay.portal.kernel.util.ListUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.TextFormatter;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.kernel.xml.Attribute;
030    import com.liferay.portal.kernel.xml.Document;
031    import com.liferay.portal.kernel.xml.DocumentException;
032    import com.liferay.portal.kernel.xml.Element;
033    import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
034    import com.liferay.portal.tools.servicebuilder.ServiceBuilder;
035    
036    import java.io.ByteArrayInputStream;
037    import java.io.File;
038    import java.io.InputStream;
039    
040    import java.util.ArrayList;
041    import java.util.HashMap;
042    import java.util.HashSet;
043    import java.util.List;
044    import java.util.Map;
045    import java.util.Properties;
046    import java.util.Set;
047    import java.util.TreeSet;
048    import java.util.regex.Matcher;
049    import java.util.regex.Pattern;
050    
051    import javax.xml.xpath.XPath;
052    import javax.xml.xpath.XPathFactory;
053    
054    import org.apache.commons.lang.StringEscapeUtils;
055    
056    /**
057     * @author Michael Hashimoto
058     */
059    public class SeleniumBuilderFileUtil {
060    
061            public SeleniumBuilderFileUtil(String baseDirName, String projectDirName) {
062                    _baseDirName = baseDirName;
063    
064                    Properties properties = new Properties();
065    
066                    try {
067                            String content = FileUtil.read(projectDirName + "/test.properties");
068    
069                            InputStream inputStream = new ByteArrayInputStream(
070                                    content.getBytes());
071    
072                            properties.load(inputStream);
073                    }
074                    catch (Exception e) {
075                            e.printStackTrace();
076                    }
077    
078                    _componentNames = ListUtil.fromArray(
079                            StringUtil.split(properties.getProperty("component.names")));
080                    _testCaseAvailablePropertyNames = ListUtil.fromArray(
081                            StringUtil.split(
082                                    properties.getProperty("test.case.available.property.names")));
083                    _testrayAvailableComponentNames = ListUtil.fromArray(
084                            StringUtil.split(
085                                    properties.getProperty("testray.available.component.names")));
086            }
087    
088            public String escapeHtml(String input) {
089                    return StringEscapeUtils.escapeHtml(input);
090            }
091    
092            public String escapeJava(String input) {
093                    return StringEscapeUtils.escapeJava(input);
094            }
095    
096            public List<Element> getAllChildElements(
097                    Element element, String elementName) {
098    
099                    List<Element> allChildElements = new ArrayList<>();
100    
101                    List<Element> childElements = element.elements();
102    
103                    if (childElements.isEmpty()) {
104                            return allChildElements;
105                    }
106    
107                    for (Element childElement : childElements) {
108                            String childElementName = childElement.getName();
109    
110                            if (childElementName.equals(elementName)) {
111                                    allChildElements.add(childElement);
112                            }
113    
114                            allChildElements.addAll(
115                                    getAllChildElements(childElement, elementName));
116                    }
117    
118                    return allChildElements;
119            }
120    
121            public String getBaseDirName() {
122                    return _baseDirName;
123            }
124    
125            public Set<String> getChildElementAttributeValues(
126                    Element element, String attributeName) {
127    
128                    Set<String> childElementAttributeValues = new TreeSet<>();
129    
130                    List<Element> childElements = element.elements();
131    
132                    if (childElements.isEmpty()) {
133                            return childElementAttributeValues;
134                    }
135    
136                    for (Element childElement : childElements) {
137                            String childElementName = childElement.attributeValue(
138                                    attributeName);
139    
140                            if (childElementName != null) {
141                                    int x = childElementName.lastIndexOf(StringPool.POUND);
142    
143                                    if (x != -1) {
144                                            childElementAttributeValues.add(
145                                                    childElementName.substring(0, x));
146                                    }
147                                    else if (attributeName.equals("function")) {
148                                            childElementAttributeValues.add(childElementName);
149                                    }
150                            }
151    
152                            childElementAttributeValues.addAll(
153                                    getChildElementAttributeValues(childElement, attributeName));
154                    }
155    
156                    return childElementAttributeValues;
157            }
158    
159            public Set<String> getChildElementLineNumbers(Element element) {
160                    Set<String> childElementLineNumbers = new TreeSet<>();
161    
162                    List<Element> childElements = element.elements();
163    
164                    if (childElements.isEmpty()) {
165                            return childElementLineNumbers;
166                    }
167    
168                    for (Element childElement : childElements) {
169                            String childElementLineNumber = childElement.attributeValue(
170                                    "line-number");
171    
172                            if (childElementLineNumber != null) {
173                                    childElementLineNumbers.add(childElementLineNumber);
174                            }
175    
176                            childElementLineNumbers.addAll(
177                                    getChildElementLineNumbers(childElement));
178                    }
179    
180                    return childElementLineNumbers;
181            }
182    
183            public String getClassName(String fileName) {
184                    String classSuffix = getClassSuffix(fileName);
185    
186                    return getClassName(fileName, classSuffix);
187            }
188    
189            public String getClassName(String fileName, String classSuffix) {
190                    return
191                            getPackageName(fileName) + "." +
192                                    getSimpleClassName(fileName, classSuffix);
193            }
194    
195            public String getClassSimpleClassName(String className) {
196                    int x = className.lastIndexOf(CharPool.PERIOD);
197    
198                    return className.substring(x + 1);
199            }
200    
201            public String getClassSuffix(String fileName) {
202                    int x = fileName.indexOf(CharPool.PERIOD);
203    
204                    String classSuffix = StringUtil.upperCaseFirstLetter(
205                            fileName.substring(x + 1));
206    
207                    if (classSuffix.equals("Testcase")) {
208                            classSuffix = "TestCase";
209                    }
210    
211                    return classSuffix;
212            }
213    
214            public List<String> getComponentNames() {
215                    return _componentNames;
216            }
217    
218            public String getDefaultCommandName(Element rootElement) {
219                    return rootElement.attributeValue("default");
220            }
221    
222            public String getHTMLFileName(String fileName) {
223                    String javaFileName = getJavaFileName(fileName);
224    
225                    return StringUtil.replace(javaFileName, ".java", ".html");
226            }
227    
228            public String getJavaFileName(String fileName) {
229                    String classSuffix = getClassSuffix(fileName);
230    
231                    return getJavaFileName(fileName, classSuffix);
232            }
233    
234            public String getJavaFileName(String fileName, String classSuffix) {
235                    return
236                            getPackagePath(fileName) + "/" +
237                                    getSimpleClassName(fileName, classSuffix) + ".java";
238            }
239    
240            public int getLocatorCount(Element rootElement) {
241                    String xml = rootElement.asXML();
242    
243                    for (int i = 1;; i++) {
244                            if (xml.contains("${locator" + i + "}")) {
245                                    continue;
246                            }
247    
248                            if (i > 1) {
249                                    i--;
250                            }
251    
252                            return i;
253                    }
254            }
255    
256            public String getName(String fileName) {
257                    int x = fileName.lastIndexOf(StringPool.SLASH);
258                    int y = fileName.lastIndexOf(CharPool.PERIOD);
259    
260                    return fileName.substring(x + 1, y);
261            }
262    
263            public String getNormalizedContent(String fileName) throws Exception {
264                    String content = readFile(fileName);
265    
266                    if (fileName.endsWith(".path")) {
267                            int x = content.indexOf("<tbody>");
268                            int y = content.indexOf("</tbody>");
269    
270                            if ((x == -1) || (y == -1)) {
271                                    throwValidationException(1002, fileName, "tbody");
272                            }
273    
274                            String pathTbody = content.substring(x, y + 8);
275    
276                            Map<String, Object> context = new HashMap<>();
277    
278                            context.put("pathName", getName(fileName));
279                            context.put("pathTbody", pathTbody);
280    
281                            String newContent = processTemplate("path_xml.ftl", context);
282    
283                            if (!content.equals(newContent)) {
284                                    content = newContent;
285    
286                                    writeFile(getBaseDirName(), fileName, newContent, false);
287                            }
288                    }
289    
290                    StringBundler sb = new StringBundler();
291    
292                    int lineNumber = 1;
293    
294                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
295                            new UnsyncStringReader(content));
296    
297                    String line = null;
298    
299                    while ((line = unsyncBufferedReader.readLine()) != null) {
300                            Matcher matcher = _tagPattern.matcher(line);
301    
302                            if (matcher.find()) {
303                                    for (String reservedTag : _reservedTags) {
304                                            if (line.contains("<" + reservedTag)) {
305                                                    line = StringUtil.replace(
306                                                            line, matcher.group(),
307                                                            matcher.group() + " line-number=\"" + lineNumber +
308                                                                    "\"");
309    
310                                                    break;
311                                            }
312                                    }
313                            }
314    
315                            sb.append(line);
316    
317                            lineNumber++;
318                    }
319    
320                    content = sb.toString();
321    
322                    if (content != null) {
323                            content = content.trim();
324                            content = StringUtil.replace(content, "\n", "");
325                            content = StringUtil.replace(content, "\r\n", "");
326                            content = StringUtil.replace(content, "\t", " ");
327                            content = content.replaceAll(" +", " ");
328                    }
329    
330                    return content;
331            }
332    
333            public String getObjectName(String name) {
334                    return StringUtil.upperCaseFirstLetter(name);
335            }
336    
337            public String getPackageName(String fileName) {
338                    String packagePath = getPackagePath(fileName);
339    
340                    return StringUtil.replace(
341                            packagePath, StringPool.SLASH, StringPool.PERIOD);
342            }
343    
344            public String getPackagePath(String fileName) {
345                    int x = fileName.lastIndexOf(StringPool.SLASH);
346    
347                    return fileName.substring(0, x);
348            }
349    
350            public String getReturnType(String name) {
351                    if (name.startsWith("Is")) {
352                            return "boolean";
353                    }
354    
355                    return "void";
356            }
357    
358            public Element getRootElement(String fileName) throws Exception {
359                    String content = getNormalizedContent(fileName);
360    
361                    try {
362                            Document document = UnsecureSAXReaderUtil.read(content, true);
363    
364                            Element rootElement = document.getRootElement();
365    
366                            validate(fileName, rootElement);
367    
368                            return rootElement;
369                    }
370                    catch (DocumentException de) {
371                            throwValidationException(1007, fileName, de);
372                    }
373    
374                    return null;
375            }
376    
377            public String getSimpleClassName(String fileName) {
378                    String classSuffix = getClassSuffix(fileName);
379    
380                    return getSimpleClassName(fileName, classSuffix);
381            }
382    
383            public String getSimpleClassName(String fileName, String classSuffix) {
384                    return getName(fileName) + classSuffix;
385            }
386    
387            public String getVariableName(String name) {
388                    return TextFormatter.format(name, TextFormatter.I);
389            }
390    
391            public String normalizeFileName(String fileName) {
392                    return StringUtil.replace(
393                            fileName, StringPool.BACK_SLASH, StringPool.SLASH);
394            }
395    
396            public String readFile(String fileName) throws Exception {
397                    return FileUtil.read(getBaseDirName() + "/" + fileName);
398            }
399    
400            public void writeFile(String fileName, String content, boolean format)
401                    throws Exception {
402    
403                    writeFile(getBaseDirName() + "-generated", fileName, content, format);
404            }
405    
406            public void writeFile(
407                            String baseDirName, String fileName, String content, boolean format)
408                    throws Exception {
409    
410                    File file = new File(baseDirName + "/" + fileName);
411    
412                    if (format) {
413                            ServiceBuilder.writeFile(file, content);
414                    }
415                    else {
416                            System.out.println("Writing " + file);
417    
418                            FileUtil.write(file, content);
419                    }
420            }
421    
422            protected String processTemplate(String name, Map<String, Object> context)
423                    throws Exception {
424    
425                    return StringUtil.strip(
426                            FreeMarkerUtil.process(_TPL_ROOT + name, context), '\r');
427            }
428    
429            protected void throwValidationException(int errorCode, String fileName) {
430                    throwValidationException(
431                            errorCode, fileName, null, null, null, null, null);
432            }
433    
434            protected void throwValidationException(
435                    int errorCode, String fileName, Element element) {
436    
437                    throwValidationException(
438                            errorCode, fileName, element, null, null, null, null);
439            }
440    
441            protected void throwValidationException(
442                    int errorCode, String fileName, Element element, String string1) {
443    
444                    throwValidationException(
445                            errorCode, fileName, element, null, string1, null, null);
446            }
447    
448            protected void throwValidationException(
449                    int errorCode, String fileName, Element element, String string1,
450                    String string2) {
451    
452                    throwValidationException(
453                            errorCode, fileName, element, null, string1, string2, null);
454            }
455    
456            protected void throwValidationException(
457                    int errorCode, String fileName, Element element, String[] array) {
458    
459                    throwValidationException(
460                            errorCode, fileName, element, array, null, null, null);
461            }
462    
463            protected void throwValidationException(
464                    int errorCode, String fileName, Element element, String[] array,
465                    String string1) {
466    
467                    throwValidationException(
468                            errorCode, fileName, element, array, string1, null, null);
469            }
470    
471            protected void throwValidationException(
472                    int errorCode, String fileName, Element element, String[] array,
473                    String string1, String string2, Exception e) {
474    
475                    String prefix = "Error " + errorCode + ": ";
476                    String suffix = fileName;
477    
478                    if (element != null) {
479                            suffix += ":" + element.attributeValue("line-number");
480                    }
481    
482                    if (errorCode == 1000) {
483                            throw new IllegalArgumentException(
484                                    prefix + "Invalid root element in " + suffix);
485                    }
486                    else if (errorCode == 1001) {
487                            throw new IllegalArgumentException(
488                                    prefix + "Missing (" + StringUtil.merge(array, "|") +
489                                            ") child element in " + suffix);
490                    }
491                    else if (errorCode == 1002) {
492                            throw new IllegalArgumentException(
493                                    prefix + "Invalid " + string1 + " element in " + suffix);
494                    }
495                    else if (errorCode == 1003) {
496                            throw new IllegalArgumentException(
497                                    prefix + "Missing " + string1 + " attribute in " + suffix);
498                    }
499                    else if (errorCode == 1004) {
500                            throw new IllegalArgumentException(
501                                    prefix + "Missing (" + StringUtil.merge(array, "|") +
502                                            ") attribute in " + suffix);
503                    }
504                    else if (errorCode == 1005) {
505                            throw new IllegalArgumentException(
506                                    prefix + "Invalid " + string1 + " attribute in " + suffix);
507                    }
508                    else if (errorCode == 1006) {
509                            throw new IllegalArgumentException(
510                                    prefix + "Invalid " + string1 + " attribute value in " +
511                                            suffix);
512                    }
513                    else if (errorCode == 1007) {
514                            throw new IllegalArgumentException(
515                                    prefix + "Poorly formed XML in " + suffix, e);
516                    }
517                    else if (errorCode == 1008) {
518                            throw new IllegalArgumentException(
519                                    prefix + "Duplicate file name " + string1 + " at " + suffix);
520                    }
521                    else if (errorCode == 1009) {
522                            throw new IllegalArgumentException(
523                                    prefix + "Duplicate command name " + string1 + " at " + suffix);
524                    }
525                    else if (errorCode == 1010) {
526                            throw new IllegalArgumentException(
527                                    prefix + "Invalid locator-key " + string1 + " at " + suffix);
528                    }
529                    else if (errorCode == 1011) {
530                            throw new IllegalArgumentException(
531                                    prefix + "Invalid " + string1 + " name " + string2 + " at " +
532                                            suffix);
533                    }
534                    else if (errorCode == 1012) {
535                            throw new IllegalArgumentException(
536                                    prefix + "Invalid " + string1 + " command " + string2 + " at " +
537                                            suffix);
538                    }
539                    else if (errorCode == 1013) {
540                            throw new IllegalArgumentException(
541                                    prefix + "Invalid method " + string1 + " at " + suffix);
542                    }
543                    else if (errorCode == 1014) {
544                            throw new IllegalArgumentException(
545                                    prefix + "Invalid path " + string1 + " at " + suffix);
546                    }
547                    else if (errorCode == 1015) {
548                            throw new IllegalArgumentException(
549                                    prefix + "Poorly formed test case command " + string1 + " at " +
550                                            suffix);
551                    }
552                    else if (errorCode == 1016) {
553                            throw new IllegalArgumentException(
554                                    prefix + "Invalid " + string1 + " attribute value " + string2 +
555                                            " in " + suffix);
556                    }
557                    else if (errorCode == 1017) {
558                            throw new IllegalArgumentException(
559                                    prefix + "Description '" + string1 +
560                                            "' must end with a '.' in " + suffix);
561                    }
562                    else if (errorCode == 1018) {
563                            throw new IllegalArgumentException(
564                                    prefix + "Missing (" + StringUtil.merge(array, "|") +
565                                            ") in attribute " + string1 + " at " + suffix);
566                    }
567                    else if (errorCode == 2000) {
568                            throw new IllegalArgumentException(
569                                    prefix + "Too many child elements in the " + string1 +
570                                            " element in " + suffix);
571                    }
572                    else if (errorCode == 2001) {
573                            throw new IllegalArgumentException(
574                                    prefix + "Action command " + string1 +
575                                            " does not match a function name at " + suffix);
576                    }
577                    else if (errorCode == 2002) {
578                            throw new IllegalArgumentException(
579                                    prefix + "Missing matching " + string1 + ".path for " + suffix);
580                    }
581                    else if (errorCode == 2003) {
582                            throw new IllegalArgumentException(
583                                    prefix + "Illegal XPath " + string1 + " in " + suffix);
584                    }
585                    else if (errorCode == 2004) {
586                            throw new IllegalArgumentException(
587                                    prefix + "Description '" + string1 +
588                                            "' must title convention in " + suffix);
589                    }
590                    else if (errorCode == 3001) {
591                            throw new IllegalArgumentException(
592                                    prefix + "The property '" + string1 +
593                                            "' has an invalid component name '" + string2 + "' in " +
594                                                    suffix);
595                    }
596                    else if (errorCode == 3002) {
597                            throw new IllegalArgumentException(
598                                    prefix + "Missing property '" + string1 + "' for " + suffix);
599                    }
600                    else if (errorCode == 3003) {
601                            throw new IllegalArgumentException(
602                                    prefix + "Invalid property " + string1 + " at " + suffix);
603                    }
604                    else {
605                            throw new IllegalArgumentException(prefix + suffix);
606                    }
607            }
608    
609            protected void throwValidationException(
610                    int errorCode, String fileName, Exception e) {
611    
612                    throwValidationException(
613                            errorCode, fileName, null, null, null, null, e);
614            }
615    
616            protected void throwValidationException(
617                    int errorCode, String fileName, String string1) {
618    
619                    throwValidationException(
620                            errorCode, fileName, null, null, string1, null, null);
621            }
622    
623            protected void validate(String fileName, Element rootElement)
624                    throws Exception {
625    
626                    if (fileName.endsWith(".action")) {
627                            validateActionDocument(fileName, rootElement);
628                    }
629                    else if (fileName.endsWith(".function")) {
630                            validateFunctionDocument(fileName, rootElement);
631                    }
632                    else if (fileName.endsWith(".macro")) {
633                            validateMacroDocument(fileName, rootElement);
634                    }
635                    else if (fileName.endsWith(".path")) {
636                            validatePathDocument(fileName, rootElement);
637                    }
638                    else if (fileName.endsWith(".testcase")) {
639                            validateTestCaseDocument(fileName, rootElement);
640                    }
641            }
642    
643            protected void validateActionCommandElement(
644                    String fileName, Element commandElement,
645                    String[] allowedBlockChildElementNames,
646                    String[] allowedExecuteAttributeNames,
647                    String[] allowedExecuteChildElementNames) {
648    
649                    List<Element> elements = commandElement.elements();
650    
651                    if (elements.isEmpty()) {
652                            throwValidationException(
653                                    1001, fileName, commandElement,
654                                    new String[] {"case", "default"});
655                    }
656    
657                    for (Element element : elements) {
658                            List<Element> descriptionElements = element.elements("description");
659    
660                            String elementName = element.getName();
661    
662                            if (descriptionElements.size() > 1) {
663                                    throwValidationException(
664                                            2000, fileName, descriptionElements.get(1), elementName);
665                            }
666    
667                            List<Element> executeChildElements = element.elements("execute");
668    
669                            if (executeChildElements.size() > 1) {
670                                    throwValidationException(
671                                            2000, fileName, executeChildElements.get(1), elementName);
672                            }
673    
674                            if (elementName.equals("case")) {
675                                    List<Attribute> attributes = element.attributes();
676    
677                                    boolean hasNeededAttributeName = false;
678    
679                                    for (Attribute attribute : attributes) {
680                                            String attributeName = attribute.getName();
681    
682                                            if (attributeName.equals("comparator")) {
683                                                    String attributeValue = attribute.getValue();
684    
685                                                    if (!attributeValue.equals("contains") &&
686                                                            !attributeValue.equals("endsWith") &&
687                                                            !attributeValue.equals("equals") &&
688                                                            !attributeValue.equals("startsWith")) {
689    
690                                                            throwValidationException(
691                                                                    1006, fileName, element, attributeName);
692                                                    }
693                                            }
694                                            else if (attributeName.equals("locator1") ||
695                                                             attributeName.equals("locator2") ||
696                                                             attributeName.equals("locator-key1") ||
697                                                             attributeName.equals("locator-key2") ||
698                                                             attributeName.equals("value1") ||
699                                                             attributeName.equals("value2")) {
700    
701                                                    String attributeValue = attribute.getValue();
702    
703                                                    if (Validator.isNull(attributeValue)) {
704                                                            throwValidationException(
705                                                                    1006, fileName, element, attributeName);
706                                                    }
707    
708                                                    hasNeededAttributeName = true;
709                                            }
710    
711                                            if (!attributeName.equals("comparator") &&
712                                                    !attributeName.equals("line-number") &&
713                                                    !attributeName.equals("locator1") &&
714                                                    !attributeName.equals("locator2") &&
715                                                    !attributeName.equals("locator-key1") &&
716                                                    !attributeName.equals("locator-key2") &&
717                                                    !attributeName.equals("value1") &&
718                                                    !attributeName.equals("value2")) {
719    
720                                                    throwValidationException(
721                                                            1005, fileName, element, attributeName);
722                                            }
723    
724                                            if (attributeName.equals("locator") ||
725                                                    attributeName.equals("locator-key") ||
726                                                    attributeName.equals("value")) {
727    
728                                                    throwValidationException(
729                                                            1005, fileName, element, attributeName);
730                                            }
731                                    }
732    
733                                    if (!hasNeededAttributeName) {
734                                            throwValidationException(
735                                                    1004, fileName, element,
736                                                    new String[] {"locator1", "locator-key1", "value1"});
737                                    }
738    
739                                    validateBlockElement(
740                                            fileName, element, new String[] {"execute"},
741                                            new String[] {"function"}, new String[0], new String[0]);
742                            }
743                            else if (elementName.equals("default")) {
744                                    List<Attribute> attributes = element.attributes();
745    
746                                    if (attributes.size() != 1) {
747                                            Attribute attribute = attributes.get(1);
748    
749                                            String attributeName = attribute.getName();
750    
751                                            throwValidationException(
752                                                    1005, fileName, element, attributeName);
753                                    }
754    
755                                    validateBlockElement(
756                                            fileName, element, new String[] {"description", "execute"},
757                                            new String[] {"function"}, new String[0], new String[0]);
758                            }
759                            else {
760                                    throwValidationException(1002, fileName, element, elementName);
761                            }
762                    }
763            }
764    
765            protected void validateActionDocument(
766                    String fileName, Element rootElement) {
767    
768                    if (!Validator.equals(rootElement.getName(), "definition")) {
769                            throwValidationException(1000, fileName, rootElement);
770                    }
771    
772                    List<Element> elements = rootElement.elements();
773    
774                    if (elements.isEmpty()) {
775                            throwValidationException(
776                                    1001, fileName, rootElement, new String[] {"command"});
777                    }
778    
779                    for (Element element : elements) {
780                            String elementName = element.getName();
781    
782                            if (elementName.equals("command")) {
783                                    String attributeValue = element.attributeValue("name");
784    
785                                    if (attributeValue == null) {
786                                            throwValidationException(1003, fileName, element, "name");
787                                    }
788                                    else if (Validator.isNull(attributeValue)) {
789                                            throwValidationException(1006, fileName, element, "name");
790                                    }
791    
792                                    validateActionCommandElement(
793                                            fileName, element, new String[] {"execute"},
794                                            new String[] {"function"}, new String[0]);
795                            }
796                            else {
797                                    throwValidationException(1002, fileName, element, elementName);
798                            }
799                    }
800            }
801    
802            protected void validateBlockElement(
803                    String fileName, Element commandElement,
804                    String[] allowedBlockChildElementNames,
805                    String[] allowedExecuteAttributeNames,
806                    String[] allowedExecuteChildElementNames,
807                    String[] allowedIfConditionElementNames) {
808    
809                    List<Element> elements = commandElement.elements();
810    
811                    if (elements.isEmpty()) {
812                            throwValidationException(
813                                    1001, fileName, commandElement, allowedBlockChildElementNames);
814                    }
815    
816                    for (Element element : elements) {
817                            String elementName = element.getName();
818    
819                            if (!ArrayUtil.contains(
820                                            allowedBlockChildElementNames, elementName)) {
821    
822                                    throwValidationException(1002, fileName, element, elementName);
823                            }
824    
825                            if (elementName.equals("description")) {
826                                    validateSimpleElement(
827                                            fileName, element, new String[] {"message"});
828    
829                                    String message = element.attributeValue("message");
830    
831                                    if (!message.endsWith(".")) {
832                                            throwValidationException(
833                                                    1017, fileName, commandElement, message);
834                                    }
835                            }
836                            else if (elementName.equals("echo") || elementName.equals("fail")) {
837                                    validateSimpleElement(
838                                            fileName, element, new String[] {"message"});
839                            }
840                            else if (elementName.equals("execute")) {
841                                    validateExecuteElement(
842                                            fileName, element, allowedExecuteAttributeNames, ".+",
843                                            allowedExecuteChildElementNames);
844                            }
845                            else if (elementName.equals("for")) {
846                                    validateForElement(
847                                            fileName, element, new String[] {"list", "param"},
848                                            allowedBlockChildElementNames, allowedExecuteAttributeNames,
849                                            allowedExecuteChildElementNames,
850                                            allowedIfConditionElementNames);
851                            }
852                            else if (elementName.equals("if") || elementName.equals("while")) {
853                                    validateIfElement(
854                                            fileName, element, allowedBlockChildElementNames,
855                                            allowedExecuteAttributeNames,
856                                            allowedExecuteChildElementNames,
857                                            allowedIfConditionElementNames);
858                            }
859                            else if (elementName.equals("property")) {
860                                    validatePropertyElement(fileName, element);
861                            }
862                            else if (elementName.equals("take-screenshot")) {
863                                    validateSimpleElement(fileName, element, new String[0]);
864                            }
865                            else if (elementName.equals("task")) {
866                                    validateBlockElement(
867                                            fileName, element, allowedBlockChildElementNames,
868                                            allowedExecuteAttributeNames,
869                                            allowedExecuteChildElementNames,
870                                            allowedIfConditionElementNames);
871                            }
872                            else if (elementName.equals("var")) {
873                                    validateVarElement(fileName, element);
874                            }
875                            else {
876                                    throwValidationException(1002, fileName, element, elementName);
877                            }
878                    }
879            }
880    
881            protected void validateExecuteElement(
882                    String fileName, Element executeElement,
883                    String[] allowedExecuteAttributeNames,
884                    String allowedExecuteAttributeValuesRegex,
885                    String[] allowedExecuteChildElementNames) {
886    
887                    boolean hasAllowedAttributeName = false;
888    
889                    List<Attribute> attributes = executeElement.attributes();
890    
891                    for (Attribute attribute : attributes) {
892                            String attributeName = attribute.getName();
893    
894                            if (ArrayUtil.contains(
895                                            allowedExecuteAttributeNames, attributeName)) {
896    
897                                    hasAllowedAttributeName = true;
898    
899                                    break;
900                            }
901                    }
902    
903                    if (!hasAllowedAttributeName) {
904                            throwValidationException(
905                                    1004, fileName, executeElement, allowedExecuteAttributeNames);
906                    }
907    
908                    String action = executeElement.attributeValue("action");
909                    String function = executeElement.attributeValue("function");
910                    String macro = executeElement.attributeValue("macro");
911                    String macroDesktop = executeElement.attributeValue("macro-desktop");
912                    String macroMobile = executeElement.attributeValue("macro-mobile");
913                    String selenium = executeElement.attributeValue("selenium");
914                    String testCase = executeElement.attributeValue("test-case");
915                    String testCaseCommand = executeElement.attributeValue(
916                            "test-case-command");
917                    String testClass = executeElement.attributeValue("test-class");
918    
919                    if (action != null) {
920                            if (Validator.isNull(action) ||
921                                    !action.matches(allowedExecuteAttributeValuesRegex)) {
922    
923                                    throwValidationException(
924                                            1006, fileName, executeElement, "action");
925                            }
926    
927                            for (Attribute attribute : attributes) {
928                                    String attributeName = attribute.getName();
929    
930                                    if (!attributeName.equals("action") &&
931                                            !attributeName.equals("line-number") &&
932                                            !attributeName.equals("locator1") &&
933                                            !attributeName.equals("locator2") &&
934                                            !attributeName.equals("locator-key1") &&
935                                            !attributeName.equals("locator-key2") &&
936                                            !attributeName.equals("value1") &&
937                                            !attributeName.equals("value2")) {
938    
939                                            throwValidationException(
940                                                    1005, fileName, executeElement, attributeName);
941                                    }
942    
943                                    if (attributeName.equals("locator") ||
944                                            attributeName.equals("locator-key") ||
945                                            attributeName.equals("value")) {
946    
947                                            throwValidationException(
948                                                    1005, fileName, executeElement, attributeName);
949                                    }
950    
951                                    String attributeValue = attribute.getValue();
952    
953                                    if (attributeName.equals("value1") &&
954                                            attributeValue.contains("move-file")) {
955    
956                                            if (!attributeValue.contains("-Dfile") ||
957                                                    !attributeValue.contains("-Dtofile")) {
958    
959                                                    throwValidationException(
960                                                            1018, fileName, executeElement,
961                                                            new String[] {"-Dfile", "-Dtofile"}, "value1");
962                                            }
963                                    }
964    
965                                    if (attributeName.equals("value1") &&
966                                            attributeValue.contains("replace-file")) {
967    
968                                            if (!attributeValue.contains("-Dfile") ||
969                                                    !attributeValue.contains("-Dtoken") ||
970                                                    !attributeValue.contains("-Dvalue")) {
971    
972                                                    throwValidationException(
973                                                            1018, fileName, executeElement,
974                                                            new String[] {"-Dfile", "-Dtoken", "-Dvalue"},
975                                                            "value1");
976                                            }
977                                    }
978                            }
979                    }
980                    else if (function != null) {
981                            if (Validator.isNull(function) ||
982                                    !function.matches(allowedExecuteAttributeValuesRegex)) {
983    
984                                    throwValidationException(
985                                            1006, fileName, executeElement, "function");
986                            }
987    
988                            for (Attribute attribute : attributes) {
989                                    String attributeName = attribute.getName();
990    
991                                    if (!attributeName.equals("function") &&
992                                            !attributeName.equals("ignore-javascript-error") &&
993                                            !attributeName.equals("line-number") &&
994                                            !attributeName.startsWith("locator") &&
995                                            !attributeName.startsWith("value")) {
996    
997                                            throwValidationException(
998                                                    1005, fileName, executeElement, attributeName);
999                                    }
1000    
1001                                    if (attributeName.equals("locator") ||
1002                                            attributeName.equals("value") ||
1003                                            attributeName.startsWith("locator-key")) {
1004    
1005                                            throwValidationException(
1006                                                    1005, fileName, executeElement, attributeName);
1007                                    }
1008                            }
1009                    }
1010                    else if (macro != null) {
1011                            if (Validator.isNull(macro) ||
1012                                    !macro.matches(allowedExecuteAttributeValuesRegex)) {
1013    
1014                                    throwValidationException(
1015                                            1006, fileName, executeElement, "macro");
1016                            }
1017    
1018                            for (Attribute attribute : attributes) {
1019                                    String attributeName = attribute.getName();
1020    
1021                                    if (!attributeName.equals("line-number") &&
1022                                            !attributeName.equals("macro")) {
1023    
1024                                            throwValidationException(
1025                                                    1005, fileName, executeElement, attributeName);
1026                                    }
1027                            }
1028                    }
1029                    else if (macroDesktop != null) {
1030                            if (Validator.isNull(macroDesktop) ||
1031                                    !macroDesktop.matches(allowedExecuteAttributeValuesRegex)) {
1032    
1033                                    throwValidationException(
1034                                            1006, fileName, executeElement, "macro-desktop");
1035                            }
1036    
1037                            for (Attribute attribute : attributes) {
1038                                    String attributeName = attribute.getName();
1039    
1040                                    if (!attributeName.equals("line-number") &&
1041                                            !attributeName.equals("macro-desktop") &&
1042                                            !attributeName.equals("macro-mobile")) {
1043    
1044                                            throwValidationException(
1045                                                    1005, fileName, executeElement, attributeName);
1046                                    }
1047                            }
1048                    }
1049                    else if (macroMobile != null) {
1050                            if (Validator.isNull(macroMobile) ||
1051                                    !macroMobile.matches(allowedExecuteAttributeValuesRegex)) {
1052    
1053                                    throwValidationException(
1054                                            1006, fileName, executeElement, "macro-mobile");
1055                            }
1056    
1057                            for (Attribute attribute : attributes) {
1058                                    String attributeName = attribute.getName();
1059    
1060                                    if (!attributeName.equals("line-number") &&
1061                                            !attributeName.equals("macro")) {
1062    
1063                                            throwValidationException(
1064                                                    1005, fileName, executeElement, attributeName);
1065                                    }
1066                            }
1067                    }
1068                    else if (selenium != null) {
1069                            if (Validator.isNull(selenium) ||
1070                                    !selenium.matches(allowedExecuteAttributeValuesRegex)) {
1071    
1072                                    throwValidationException(
1073                                            1006, fileName, executeElement, "selenium");
1074                            }
1075    
1076                            for (Attribute attribute : attributes) {
1077                                    String attributeName = attribute.getName();
1078    
1079                                    if (!attributeName.equals("argument1") &&
1080                                            !attributeName.equals("argument2") &&
1081                                            !attributeName.equals("line-number") &&
1082                                            !attributeName.equals("selenium")) {
1083    
1084                                            throwValidationException(
1085                                                    1005, fileName, executeElement, attributeName);
1086                                    }
1087                            }
1088                    }
1089                    else if (testCase != null) {
1090                            if (Validator.isNull(testCase) ||
1091                                    !testCase.matches(allowedExecuteAttributeValuesRegex)) {
1092    
1093                                    throwValidationException(
1094                                            1006, fileName, executeElement, "test-case");
1095                            }
1096    
1097                            if (testCase.contains("#")) {
1098                                    int x = testCase.lastIndexOf("#");
1099    
1100                                    if (x == -1) {
1101                                            throwValidationException(
1102                                                    1015, fileName, executeElement, testCaseCommand);
1103                                    }
1104    
1105                                    String testCaseName = testCase.substring(0, x);
1106    
1107                                    String testCaseCommandName = testCase.substring(x + 1);
1108    
1109                                    if (Validator.isNull(testCaseCommandName) ||
1110                                            Validator.isNull(testCaseName) ||
1111                                            !testCaseName.equals("super")) {
1112    
1113                                            throwValidationException(
1114                                                    1015, fileName, executeElement, testCase);
1115                                    }
1116                            }
1117                            else {
1118                                    throwValidationException(
1119                                            1015, fileName, executeElement, testCase);
1120                            }
1121    
1122                            for (Attribute attribute : attributes) {
1123                                    String attributeName = attribute.getName();
1124    
1125                                    if (!attributeName.equals("line-number") &&
1126                                            !attributeName.equals("test-case")) {
1127    
1128                                            throwValidationException(
1129                                                    1005, fileName, executeElement, attributeName);
1130                                    }
1131                            }
1132                    }
1133                    else if (testCaseCommand != null) {
1134                            if (Validator.isNull(testCaseCommand) ||
1135                                    !testCaseCommand.matches(allowedExecuteAttributeValuesRegex)) {
1136    
1137                                    throwValidationException(
1138                                            1006, fileName, executeElement, "test-case-command");
1139                            }
1140    
1141                            if (testCaseCommand.contains("#")) {
1142                                    int x = testCaseCommand.lastIndexOf("#");
1143    
1144                                    String testCaseName = testCaseCommand.substring(0, x);
1145    
1146                                    String testCaseCommandName = testCaseCommand.substring(x + 1);
1147    
1148                                    if (Validator.isNull(testCaseCommandName) ||
1149                                            Validator.isNull(testCaseName)) {
1150    
1151                                            throwValidationException(
1152                                                    1015, fileName, executeElement, testCaseCommand);
1153                                    }
1154                            }
1155                            else {
1156                                    throwValidationException(
1157                                            1015, fileName, executeElement, testCaseCommand);
1158                            }
1159    
1160                            for (Attribute attribute : attributes) {
1161                                    String attributeName = attribute.getName();
1162    
1163                                    if (!attributeName.equals("line-number") &&
1164                                            !attributeName.equals("test-case-command")) {
1165    
1166                                            throwValidationException(
1167                                                    1005, fileName, executeElement, attributeName);
1168                                    }
1169                            }
1170                    }
1171                    else if (testClass != null) {
1172                            if (Validator.isNull(testClass) ||
1173                                    !testClass.matches(allowedExecuteAttributeValuesRegex)) {
1174    
1175                                    throwValidationException(
1176                                            1006, fileName, executeElement, "test-class");
1177                            }
1178    
1179                            for (Attribute attribute : attributes) {
1180                                    String attributeName = attribute.getName();
1181    
1182                                    if (!attributeName.equals("line-number") &&
1183                                            !attributeName.equals("test-class")) {
1184    
1185                                            throwValidationException(
1186                                                    1005, fileName, executeElement, attributeName);
1187                                    }
1188                            }
1189                    }
1190                    else {
1191                            throwValidationException(0, fileName);
1192                    }
1193    
1194                    List<Element> elements = executeElement.elements();
1195    
1196                    if (allowedExecuteChildElementNames.length == 0) {
1197                            if (!elements.isEmpty()) {
1198                                    Element element = elements.get(0);
1199    
1200                                    String elementName = element.getName();
1201    
1202                                    throwValidationException(1002, fileName, element, elementName);
1203                            }
1204                    }
1205                    else {
1206                            String executeElementName = executeElement.getName();
1207    
1208                            for (Element element : elements) {
1209                                    String elementName = element.getName();
1210    
1211                                    if (executeElementName.equals("condition")) {
1212                                            throwValidationException(
1213                                                    1002, fileName, element, elementName);
1214                                    }
1215    
1216                                    if (elementName.equals("var")) {
1217                                            validateVarElement(fileName, element);
1218                                    }
1219                                    else {
1220                                            throwValidationException(
1221                                                    1002, fileName, element, elementName);
1222                                    }
1223                            }
1224                    }
1225            }
1226    
1227            protected void validateForElement(
1228                    String fileName, Element forElement, String[] neededAttributes,
1229                    String[] allowedBlockChildElementNames,
1230                    String[] allowedExecuteAttributeNames,
1231                    String[] allowedExecuteChildElementNames,
1232                    String[] allowedIfConditionElementNames) {
1233    
1234                    Map<String, Boolean> hasNeededAttributes = new HashMap<>();
1235    
1236                    for (String neededAttribute : neededAttributes) {
1237                            hasNeededAttributes.put(neededAttribute, false);
1238                    }
1239    
1240                    List<Attribute> attributes = forElement.attributes();
1241    
1242                    for (Attribute attribute : attributes) {
1243                            String attributeName = attribute.getName();
1244                            String attributeValue = attribute.getValue();
1245    
1246                            if (!_allowedNullAttributes.contains(attributeName) &&
1247                                    Validator.isNull(attributeValue)) {
1248    
1249                                    throwValidationException(
1250                                            1006, fileName, forElement, attributeName);
1251                            }
1252    
1253                            if (hasNeededAttributes.containsKey(attributeName)) {
1254                                    hasNeededAttributes.put(attributeName, true);
1255                            }
1256    
1257                            if (!attributeName.equals("line-number") &&
1258                                    !hasNeededAttributes.containsKey(attributeName)) {
1259    
1260                                    throwValidationException(
1261                                            1005, fileName, forElement, attributeName);
1262                            }
1263                    }
1264    
1265                    for (String neededAttribute : neededAttributes) {
1266                            if (!hasNeededAttributes.get(neededAttribute)) {
1267                                    throwValidationException(
1268                                            1004, fileName, forElement, neededAttributes);
1269                            }
1270                    }
1271    
1272                    validateBlockElement(
1273                            fileName, forElement, allowedBlockChildElementNames,
1274                            allowedExecuteAttributeNames, allowedExecuteChildElementNames,
1275                            allowedIfConditionElementNames);
1276            }
1277    
1278            protected void validateFunctionDocument(
1279                    String fileName, Element rootElement) {
1280    
1281                    if (!Validator.equals(rootElement.getName(), "definition")) {
1282                            throwValidationException(1000, fileName, rootElement);
1283                    }
1284    
1285                    String defaultCommandName = getDefaultCommandName(rootElement);
1286    
1287                    if (defaultCommandName == null) {
1288                            throwValidationException(1003, fileName, rootElement, "default");
1289                    }
1290    
1291                    List<Element> elements = rootElement.elements();
1292    
1293                    if (elements.isEmpty()) {
1294                            throwValidationException(
1295                                    1001, fileName, rootElement, new String[] {"command"});
1296                    }
1297    
1298                    for (Element element : elements) {
1299                            String elementName = element.getName();
1300    
1301                            if (elementName.equals("command")) {
1302                                    String attributeValue = element.attributeValue("name");
1303    
1304                                    if (attributeValue == null) {
1305                                            throwValidationException(1003, fileName, element, "name");
1306                                    }
1307                                    else if (Validator.isNull(attributeValue)) {
1308                                            throwValidationException(1006, fileName, element, "name");
1309                                    }
1310    
1311                                    validateBlockElement(
1312                                            fileName, element, new String[] {"execute", "if"},
1313                                            new String[] {"function", "selenium"}, new String[0],
1314                                            new String[] {"condition", "contains"});
1315                            }
1316                            else {
1317                                    throwValidationException(1002, fileName, element, elementName);
1318                            }
1319                    }
1320            }
1321    
1322            protected void validateIfElement(
1323                    String fileName, Element ifElement,
1324                    String[] allowedBlockChildElementNames,
1325                    String[] allowedExecuteAttributeNames,
1326                    String[] allowedExecuteChildElementNames,
1327                    String[] allowedIfConditionElementNames) {
1328    
1329                    List<Element> elements = ifElement.elements();
1330    
1331                    Set<String> elementNames = new HashSet<>();
1332    
1333                    boolean hasAllowedIfConditionElementNames = false;
1334    
1335                    for (Element element : elements) {
1336                            String elementName = element.getName();
1337    
1338                            elementNames.add(elementName);
1339    
1340                            if (ArrayUtil.contains(
1341                                            allowedIfConditionElementNames, elementName)) {
1342    
1343                                    hasAllowedIfConditionElementNames = true;
1344                            }
1345    
1346                            String ifElementName = ifElement.getName();
1347    
1348                            if (elementName.equals("and") || elementName.equals("not") ||
1349                                    elementName.equals("or")) {
1350    
1351                                    validateIfElement(
1352                                            fileName, element, allowedBlockChildElementNames,
1353                                            allowedExecuteAttributeNames,
1354                                            allowedExecuteChildElementNames,
1355                                            allowedIfConditionElementNames);
1356                            }
1357                            else if (elementName.equals("condition")) {
1358                                    validateExecuteElement(
1359                                            fileName, element, allowedExecuteAttributeNames,
1360                                            ".*(is|Is).+", allowedExecuteChildElementNames);
1361                            }
1362                            else if (elementName.equals("contains")) {
1363                                    validateSimpleElement(
1364                                            fileName, element, new String[] {"string", "substring"});
1365    
1366                                    if (fileName.endsWith(".function")) {
1367                                            List<Attribute> attributes = element.attributes();
1368    
1369                                            for (Attribute attribute : attributes) {
1370                                                    String attributeValue = attribute.getValue();
1371    
1372                                                    Matcher varElementMatcher = _varElementPattern.matcher(
1373                                                            attributeValue);
1374    
1375                                                    Matcher varElementFunctionMatcher =
1376                                                            _varElementFunctionPattern.matcher(attributeValue);
1377    
1378                                                    if (varElementMatcher.find() &&
1379                                                            !varElementFunctionMatcher.find()) {
1380    
1381                                                            throwValidationException(
1382                                                                    1006, fileName, element, attribute.getName());
1383                                                    }
1384                                            }
1385                                    }
1386                            }
1387                            else if (elementName.equals("else")) {
1388                                    if (ifElementName.equals("while")) {
1389                                            throwValidationException(
1390                                                    1002, fileName, element, elementName);
1391                                    }
1392    
1393                                    validateBlockElement(
1394                                            fileName, element, allowedBlockChildElementNames,
1395                                            allowedExecuteAttributeNames,
1396                                            allowedExecuteChildElementNames,
1397                                            allowedIfConditionElementNames);
1398                            }
1399                            else if (elementName.equals("elseif")) {
1400                                    if (ifElementName.equals("while")) {
1401                                            throwValidationException(
1402                                                    1002, fileName, element, elementName);
1403                                    }
1404    
1405                                    validateIfElement(
1406                                            fileName, element, allowedBlockChildElementNames,
1407                                            allowedExecuteAttributeNames,
1408                                            allowedExecuteChildElementNames,
1409                                            allowedIfConditionElementNames);
1410                            }
1411                            else if (elementName.equals("equals")) {
1412                                    validateSimpleElement(
1413                                            fileName, element, new String[] {"arg1", "arg2"});
1414                            }
1415                            else if (elementName.equals("isset")) {
1416                                    validateSimpleElement(fileName, element, new String[] {"var"});
1417                            }
1418                            else if (elementName.equals("then")) {
1419                                    validateBlockElement(
1420                                            fileName, element, allowedBlockChildElementNames,
1421                                            allowedExecuteAttributeNames,
1422                                            allowedExecuteChildElementNames,
1423                                            allowedIfConditionElementNames);
1424                            }
1425                            else {
1426                                    throwValidationException(1002, fileName, element, elementName);
1427                            }
1428                    }
1429    
1430                    if (!hasAllowedIfConditionElementNames) {
1431                            throwValidationException(
1432                                    1001, fileName, ifElement, allowedIfConditionElementNames);
1433                    }
1434    
1435                    if (Validator.equals(ifElement.getName(), "and") ||
1436                            Validator.equals(ifElement.getName(), "not") ||
1437                            Validator.equals(ifElement.getName(), "or")) {
1438    
1439                            return;
1440                    }
1441    
1442                    if (!elementNames.contains("then")) {
1443                            throwValidationException(
1444                                    1001, fileName, ifElement, new String[] {"then"});
1445                    }
1446            }
1447    
1448            protected void validateMacroDocument(String fileName, Element rootElement) {
1449                    if (!Validator.equals(rootElement.getName(), "definition")) {
1450                            throwValidationException(1000, fileName, rootElement);
1451                    }
1452    
1453                    List<Element> elements = rootElement.elements();
1454    
1455                    String extendsName = rootElement.attributeValue("extends");
1456    
1457                    if (elements.isEmpty() && (extendsName == null)) {
1458                            throwValidationException(
1459                                    1001, fileName, rootElement, new String[] {"command", "var"});
1460                    }
1461                    else if (extendsName != null) {
1462                            if (Validator.isNull(extendsName)) {
1463                                    throwValidationException(
1464                                            1006, fileName, rootElement, "extends");
1465                            }
1466                    }
1467    
1468                    for (Element element : elements) {
1469                            String elementName = element.getName();
1470    
1471                            if (elementName.equals("command")) {
1472                                    String attributeValue = element.attributeValue("name");
1473    
1474                                    if (attributeValue == null) {
1475                                            throwValidationException(1003, fileName, element, "name");
1476                                    }
1477                                    else if (Validator.isNull(attributeValue)) {
1478                                            throwValidationException(1006, fileName, element, "name");
1479                                    }
1480    
1481                                    validateBlockElement(
1482                                            fileName, element,
1483                                            new String[] {
1484                                                    "description", "echo", "execute", "fail", "for", "if",
1485                                                    "take-screenshot", "task", "var", "while"
1486                                            },
1487                                            new String[] {
1488                                                    "action", "function", "macro", "macro-desktop",
1489                                                    "macro-mobile"
1490                                            },
1491                                            new String[] {"var"},
1492                                            new String[] {
1493                                                    "and", "condition", "contains", "equals", "isset",
1494                                                    "not", "or"
1495                                            });
1496                            }
1497                            else if (elementName.equals("var")) {
1498                                    validateVarElement(fileName, element);
1499                            }
1500                            else {
1501                                    throwValidationException(1002, fileName, element, elementName);
1502                            }
1503                    }
1504            }
1505    
1506            protected void validatePathDocument(String fileName, Element rootElement) {
1507                    Element headElement = rootElement.element("head");
1508    
1509                    Element titleElement = headElement.element("title");
1510    
1511                    String title = titleElement.getText();
1512    
1513                    int x = fileName.lastIndexOf(StringPool.SLASH);
1514                    int y = fileName.lastIndexOf(CharPool.PERIOD);
1515    
1516                    String shortFileName = fileName.substring(x + 1, y);
1517    
1518                    if ((title == null) || !shortFileName.equals(title)) {
1519                            throwValidationException(0, fileName);
1520                    }
1521    
1522                    Element bodyElement = rootElement.element("body");
1523    
1524                    Element tableElement = bodyElement.element("table");
1525    
1526                    Element theadElement = tableElement.element("thead");
1527    
1528                    Element trElement = theadElement.element("tr");
1529    
1530                    Element tdElement = trElement.element("td");
1531    
1532                    String tdText = tdElement.getText();
1533    
1534                    if ((tdText == null) || !shortFileName.equals(tdText)) {
1535                            throwValidationException(0, fileName);
1536                    }
1537    
1538                    Element tbodyElement = tableElement.element("tbody");
1539    
1540                    List<Element> elements = tbodyElement.elements();
1541    
1542                    for (Element element : elements) {
1543                            String elementName = element.getName();
1544    
1545                            if (elementName.equals("tr")) {
1546                                    validatePathTrElement(fileName, element);
1547                            }
1548                            else {
1549                                    throwValidationException(1002, fileName, element, elementName);
1550                            }
1551                    }
1552            }
1553    
1554            protected void validatePathTrElement(String fileName, Element trElement) {
1555                    List<Element> elements = trElement.elements();
1556    
1557                    for (Element element : elements) {
1558                            String elementName = element.getName();
1559    
1560                            if (!elementName.equals("td")) {
1561                                    throwValidationException(1002, fileName, element, elementName);
1562                            }
1563                    }
1564    
1565                    if (elements.size() < 3) {
1566                            throwValidationException(
1567                                    1001, fileName, trElement, new String[] {"td"});
1568                    }
1569    
1570                    if (elements.size() > 3) {
1571                            Element element = elements.get(3);
1572    
1573                            String elementName = element.getName();
1574    
1575                            throwValidationException(1002, fileName, element, elementName);
1576                    }
1577    
1578                    Element locatorElement = elements.get(1);
1579    
1580                    String locator = locatorElement.getText();
1581    
1582                    locator = locator.replace("${", "");
1583                    locator = locator.replace("}", "");
1584                    locator = locator.replace("/-/", "/");
1585    
1586                    if (locator.endsWith("/")) {
1587                            locator = locator.substring(0, locator.length() - 1);
1588                    }
1589    
1590                    if (!locator.equals("") && !locator.startsWith("link=") &&
1591                            !locator.startsWith("title=") && !locator.contains(".png")) {
1592    
1593                            try {
1594                                    XPathFactory xPathFactory = XPathFactory.newInstance();
1595    
1596                                    XPath xPath = xPathFactory.newXPath();
1597    
1598                                    xPath.compile(locator);
1599                            }
1600                            catch (Exception e) {
1601                                    throwValidationException(2003, fileName, locator);
1602                            }
1603                    }
1604    
1605                    Element keyElement = elements.get(0);
1606    
1607                    String key = keyElement.getText();
1608    
1609                    Element descriptionElement = elements.get(2);
1610    
1611                    String description = descriptionElement.getText();
1612    
1613                    if (!key.equals("") && !key.equals("EXTEND_ACTION_PATH") &&
1614                            !key.equals("PAGE_NAME") && !description.equals("")) {
1615    
1616                            if (description.endsWith(".")) {
1617                                    throwValidationException(2004, fileName, description);
1618                            }
1619    
1620                            Matcher statmentMatcher = _pathTrElementStatementPattern.matcher(
1621                                    description);
1622    
1623                            if (!statmentMatcher.find()) {
1624                                    throwValidationException(2004, fileName, description);
1625                            }
1626    
1627                            Matcher wordMatcher1 = _pathTrElementWordPattern1.matcher(
1628                                    description);
1629    
1630                            while (wordMatcher1.find()) {
1631                                    String word = wordMatcher1.group();
1632    
1633                                    if (word.equals("a") || word.equals("and") ||
1634                                            word.equals("as") || word.equals("at") ||
1635                                            word.equals("by") || word.equals("for") ||
1636                                            word.equals("from") || word.equals("in") ||
1637                                            word.equals("of") || word.equals("the") ||
1638                                            word.equals("to")) {
1639    
1640                                            continue;
1641                                    }
1642    
1643                                    Matcher wordMatcher2 = _pathTrElementWordPattern2.matcher(word);
1644    
1645                                    if (!wordMatcher2.find()) {
1646                                            throwValidationException(2004, fileName, description);
1647                                    }
1648                            }
1649                    }
1650            }
1651    
1652            protected void validatePropertyElement(
1653                    String fileName, Element propertyElement) {
1654    
1655                    List<Attribute> attributes = propertyElement.attributes();
1656    
1657                    String propertyName = propertyElement.attributeValue("name");
1658    
1659                    if (!_testCaseAvailablePropertyNames.contains(propertyName)) {
1660                            throwValidationException(
1661                                    3003, fileName, propertyElement, propertyName);
1662                    }
1663    
1664                    if (propertyName.equals("ignore.errors")) {
1665                            String propertyDelimiter = propertyElement.attributeValue(
1666                                    "delimiter");
1667    
1668                            String propertyValue = propertyElement.attributeValue("value");
1669    
1670                            if (propertyDelimiter != null) {
1671                                    if (!propertyValue.contains(propertyDelimiter)) {
1672                                            throwValidationException(
1673                                                    1006, fileName, propertyElement, "delimiter");
1674                                    }
1675                            }
1676    
1677                            if (Validator.isNull(propertyValue)) {
1678                                    throwValidationException(
1679                                            1006, fileName, propertyElement, "value");
1680                            }
1681                    }
1682    
1683                    for (Attribute attribute : attributes) {
1684                            String attributeName = attribute.getName();
1685    
1686                            if (attributeName.equals("delimiter") &&
1687                                    propertyName.equals("ignore.errors")) {
1688    
1689                                    continue;
1690                            }
1691                            else if (attributeName.equals("line-number") ||
1692                                             attributeName.equals("name") ||
1693                                             attributeName.equals("value")) {
1694    
1695                                    continue;
1696                            }
1697                            else {
1698                                    throwValidationException(
1699                                            1005, fileName, propertyElement, attributeName);
1700                            }
1701                    }
1702            }
1703    
1704            protected void validateSimpleElement(
1705                    String fileName, Element element, String[] neededAttributes) {
1706    
1707                    Map<String, Boolean> hasNeededAttributes = new HashMap<>();
1708    
1709                    for (String neededAttribute : neededAttributes) {
1710                            hasNeededAttributes.put(neededAttribute, false);
1711                    }
1712    
1713                    List<Attribute> attributes = element.attributes();
1714    
1715                    for (Attribute attribute : attributes) {
1716                            String attributeName = attribute.getName();
1717                            String attributeValue = attribute.getValue();
1718    
1719                            if (!_allowedNullAttributes.contains(attributeName) &&
1720                                    Validator.isNull(attributeValue)) {
1721    
1722                                    throwValidationException(
1723                                            1006, fileName, element, attributeName);
1724                            }
1725    
1726                            if (hasNeededAttributes.containsKey(attributeName)) {
1727                                    hasNeededAttributes.put(attributeName, true);
1728                            }
1729    
1730                            if (!attributeName.equals("line-number") &&
1731                                    !hasNeededAttributes.containsKey(attributeName)) {
1732    
1733                                    throwValidationException(
1734                                            1005, fileName, element, attributeName);
1735                            }
1736                    }
1737    
1738                    for (String neededAttribute : neededAttributes) {
1739                            if (!hasNeededAttributes.get(neededAttribute)) {
1740                                    throwValidationException(
1741                                            1004, fileName, element, neededAttributes);
1742                            }
1743                    }
1744    
1745                    List<Element> childElements = element.elements();
1746    
1747                    if (!childElements.isEmpty()) {
1748                            Element childElement = childElements.get(0);
1749    
1750                            String childElementName = childElement.getName();
1751    
1752                            throwValidationException(
1753                                    1002, fileName, childElement, childElementName);
1754                    }
1755            }
1756    
1757            protected void validateTestCaseDocument(
1758                    String fileName, Element rootElement) {
1759    
1760                    if (!Validator.equals(rootElement.getName(), "definition")) {
1761                            throwValidationException(1000, fileName, rootElement);
1762                    }
1763    
1764                    String extendedTestCase = rootElement.attributeValue("extends");
1765    
1766                    if (extendedTestCase != null) {
1767                            if (Validator.isNull(extendedTestCase)) {
1768                                    throwValidationException(
1769                                            1006, fileName, rootElement, "extends");
1770                            }
1771                    }
1772    
1773                    String componentName = rootElement.attributeValue("component-name");
1774    
1775                    if (componentName == null) {
1776                            throwValidationException(
1777                                    1003, fileName, rootElement, "component-name");
1778                    }
1779    
1780                    if ((componentName != null) &&
1781                            !_componentNames.contains(componentName)) {
1782    
1783                            throwValidationException(
1784                                    1006, fileName, rootElement, "component-name");
1785                    }
1786    
1787                    List<Element> elements = rootElement.elements();
1788    
1789                    if (Validator.isNull(extendedTestCase)) {
1790                            if (elements.isEmpty()) {
1791                                    throwValidationException(
1792                                            1001, fileName, rootElement, new String[] {"command"});
1793                            }
1794                    }
1795    
1796                    for (Element element : elements) {
1797                            String elementName = element.getName();
1798    
1799                            if (elementName.equals("command")) {
1800                                    String attributeValue = element.attributeValue("name");
1801    
1802                                    if (attributeValue == null) {
1803                                            throwValidationException(1003, fileName, element, "name");
1804                                    }
1805                                    else if (Validator.isNull(attributeValue)) {
1806                                            throwValidationException(1006, fileName, element, "name");
1807                                    }
1808    
1809                                    String priorityValue = element.attributeValue("priority");
1810    
1811                                    if (priorityValue == null) {
1812                                            throwValidationException(
1813                                                    1003, fileName, element, "priority");
1814                                    }
1815                                    else if (!(priorityValue.equals("1") ||
1816                                                       priorityValue.equals("2") ||
1817                                                       priorityValue.equals("3") ||
1818                                                       priorityValue.equals("4") ||
1819                                                       priorityValue.equals("5"))) {
1820    
1821                                            throwValidationException(
1822                                                    1006, fileName, element, "priority");
1823                                    }
1824    
1825                                    validateBlockElement(
1826                                            fileName, element,
1827                                            new String[] {
1828                                                    "description", "echo", "execute", "fail", "for", "if",
1829                                                    "property", "take-screenshot", "task", "var", "while"
1830                                            },
1831                                            new String[] {
1832                                                    "action", "function", "macro", "macro-desktop",
1833                                                    "macro-mobile", "test-case"
1834                                            },
1835                                            new String[] {"var"},
1836                                            new String[] {
1837                                                    "and", "condition", "contains", "equals", "isset",
1838                                                    "not", "or"
1839                                            });
1840                            }
1841                            else if (elementName.equals("property")) {
1842                                    validatePropertyElement(fileName, element);
1843                            }
1844                            else if (elementName.equals("set-up") ||
1845                                             elementName.equals("tear-down")) {
1846    
1847                                    List<Attribute> attributes = element.attributes();
1848    
1849                                    for (Attribute attribute : attributes) {
1850                                            String attributeName = attribute.getName();
1851    
1852                                            if (!attributeName.equals("line-number")) {
1853                                                    throwValidationException(
1854                                                            1005, fileName, element, attributeName);
1855                                            }
1856                                    }
1857    
1858                                    validateBlockElement(
1859                                            fileName, element,
1860                                            new String[] {
1861                                                    "description", "echo", "execute", "fail", "if",
1862                                                    "take-screenshot", "task", "var", "while"
1863                                            },
1864                                            new String[] {
1865                                                    "action", "function", "macro", "macro-desktop",
1866                                                    "macro-mobile", "test-case"
1867                                            },
1868                                            new String[] {"var"},
1869                                            new String[] {
1870                                                    "and", "condition", "contains", "equals", "isset",
1871                                                    "not", "or"
1872                                            });
1873                            }
1874                            else if (elementName.equals("var")) {
1875                                    validateVarElement(fileName, element);
1876                            }
1877                            else {
1878                                    throwValidationException(1002, fileName, element, elementName);
1879                            }
1880                    }
1881    
1882                    elements = getAllChildElements(rootElement, "property");
1883    
1884                    for (Element element : elements) {
1885                            String name = element.attributeValue("name");
1886                            String value = element.attributeValue("value");
1887    
1888                            if (name.equals("testray.component.names")) {
1889                                    List<String> testrayComponentNames = ListUtil.fromArray(
1890                                            StringUtil.split(value));
1891    
1892                                    for (String testrayComponentName : testrayComponentNames) {
1893                                            if (!_testrayAvailableComponentNames.contains(
1894                                                            testrayComponentName)) {
1895    
1896                                                    throwValidationException(
1897                                                            3001, fileName, element, name,
1898                                                            testrayComponentName);
1899                                            }
1900                                    }
1901                            }
1902                            else if (name.equals("testray.main.component.name")) {
1903                                    if (!_testrayAvailableComponentNames.contains(value)) {
1904                                            throwValidationException(
1905                                                    3001, fileName, element, name, value);
1906                                    }
1907                            }
1908                    }
1909    
1910                    elements = rootElement.elements("property");
1911    
1912                    boolean rootTestrayMainComponentNameFound = false;
1913    
1914                    for (Element element : elements) {
1915                            String name = element.attributeValue("name");
1916    
1917                            if (name.equals("testray.main.component.name")) {
1918                                    rootTestrayMainComponentNameFound = true;
1919    
1920                                    break;
1921                            }
1922                    }
1923    
1924                    if (!rootTestrayMainComponentNameFound) {
1925                            elements = rootElement.elements("command");
1926    
1927                            for (Element element : elements) {
1928                                    List<Element> propertyElements = getAllChildElements(
1929                                            element, "property");
1930    
1931                                    boolean commandTestrayMainComponentNameFound = false;
1932    
1933                                    for (Element propertyElement : propertyElements) {
1934                                            String propertyName = propertyElement.attributeValue(
1935                                                    "name");
1936    
1937                                            if (propertyName.equals("testray.main.component.name")) {
1938                                                    commandTestrayMainComponentNameFound = true;
1939    
1940                                                    break;
1941                                            }
1942                                    }
1943    
1944                                    if (!commandTestrayMainComponentNameFound) {
1945                                            throwValidationException(
1946                                                    3002, fileName, element, "testray.main.component.name");
1947                                    }
1948                            }
1949                    }
1950            }
1951    
1952            protected void validateVarElement(String fileName, Element element) {
1953                    List<Attribute> attributes = element.attributes();
1954    
1955                    Map<String, String> attributeMap = new HashMap<>();
1956    
1957                    for (Attribute attribute : attributes) {
1958                            String attributeName = attribute.getName();
1959                            String attributeValue = attribute.getValue();
1960    
1961                            if (!attributeName.equals("value") &&
1962                                    Validator.isNull(attributeValue)) {
1963    
1964                                    throwValidationException(
1965                                            1006, fileName, element, attributeName);
1966                            }
1967    
1968                            if (!_allowedVarAttributes.contains(attributeName)) {
1969                                    throwValidationException(
1970                                            1005, fileName, element, attributeName);
1971                            }
1972    
1973                            attributeMap.put(attributeName, attributeValue);
1974                    }
1975    
1976                    if (!attributeMap.containsKey("name")) {
1977                            throwValidationException(
1978                                    1004, fileName, element, new String[] {"name"});
1979                    }
1980                    else {
1981                            String nameValue = attributeMap.get("name");
1982    
1983                            if (Validator.isNull(nameValue)) {
1984                                    throwValidationException(1006, fileName, element, "name");
1985                            }
1986                    }
1987    
1988                    if (attributeMap.containsKey("locator")) {
1989                            String[] disallowedAttributes = {"locator-key", "path", "value"};
1990    
1991                            for (String disallowedAttribute : disallowedAttributes) {
1992                                    if (attributeMap.containsKey(disallowedAttribute)) {
1993                                            throwValidationException(
1994                                                    1005, fileName, element, disallowedAttribute);
1995                                    }
1996                            }
1997                    }
1998                    else if (attributeMap.containsKey("locator-key") &&
1999                                     attributeMap.containsKey("path")) {
2000    
2001                            if (attributeMap.containsKey("value")) {
2002                                    throwValidationException(1005, fileName, element, "value");
2003                            }
2004                    }
2005                    else if (attributeMap.containsKey("locator-key")) {
2006                            throwValidationException(
2007                                    1004, fileName, element, new String[] {"path"});
2008                    }
2009                    else if (attributeMap.containsKey("path")) {
2010                            throwValidationException(
2011                                    1004, fileName, element, new String[] {"locator-key"});
2012                    }
2013    
2014                    String varText = element.getText();
2015    
2016                    if (attributeMap.containsKey("locator") ||
2017                            attributeMap.containsKey("locator-key") ||
2018                            attributeMap.containsKey("path")) {
2019    
2020                            if (!Validator.isNull(varText)) {
2021                                    throwValidationException(1005, fileName, element, "value");
2022                            }
2023                    }
2024    
2025                    if (attributeMap.containsKey("method")) {
2026                            String methodValue = attributeMap.get("method");
2027    
2028                            if (!methodValue.startsWith("MathUtil") &&
2029                                    !methodValue.startsWith("selenium") &&
2030                                    !methodValue.startsWith("StringUtil") &&
2031                                    !methodValue.startsWith("TestPropsUtil")) {
2032    
2033                                    throwValidationException(1005, fileName, element, "method");
2034                            }
2035    
2036                            if (!methodValue.contains("#")) {
2037                                    throwValidationException(1005, fileName, element, "method");
2038                            }
2039                    }
2040    
2041                    if (!attributeMap.containsKey("property-value") &&
2042                            !attributeMap.containsKey("value") && Validator.isNull(varText)) {
2043    
2044                            if (!attributeMap.containsKey("group") &&
2045                                    !attributeMap.containsKey("input") &&
2046                                    !attributeMap.containsKey("locator") &&
2047                                    !attributeMap.containsKey("locator-key") &&
2048                                    !attributeMap.containsKey("method") &&
2049                                    !attributeMap.containsKey("path") &&
2050                                    !attributeMap.containsKey("pattern")) {
2051    
2052                                    throwValidationException(
2053                                            1004, fileName, element, new String[] {"value"});
2054                            }
2055                    }
2056                    else {
2057                            String varValue = attributeMap.get("value");
2058    
2059                            if (Validator.isNull(varValue)) {
2060                                    varValue = varText;
2061                            }
2062    
2063                            Matcher matcher = _varElementPattern.matcher(varValue);
2064    
2065                            while (matcher.find()) {
2066                                    String statement = matcher.group(1);
2067    
2068                                    Matcher statementMatcher = _varElementStatementPattern.matcher(
2069                                            statement);
2070    
2071                                    if (statementMatcher.find()) {
2072                                            String operand = statementMatcher.group(1);
2073    
2074                                            String method = statementMatcher.group(2);
2075    
2076                                            if (operand.equals("") || method.equals("")) {
2077                                                    throwValidationException(
2078                                                            1006, fileName, element, "value");
2079                                            }
2080    
2081                                            if (!_methodNames.contains(method)) {
2082                                                    throwValidationException(
2083                                                            1013, fileName, element, method);
2084                                            }
2085                                    }
2086                            }
2087                    }
2088    
2089                    List<Element> childElements = element.elements();
2090    
2091                    if (!childElements.isEmpty()) {
2092                            Element childElement = childElements.get(0);
2093    
2094                            String childElementName = childElement.getName();
2095    
2096                            throwValidationException(
2097                                    1002, fileName, childElement, childElementName);
2098                    }
2099            }
2100    
2101            private static final String _TPL_ROOT =
2102                    "com/liferay/portal/tools/seleniumbuilder/dependencies/";
2103    
2104            private static final List<String> _allowedNullAttributes =
2105                    ListUtil.fromArray(
2106                            new String[] {
2107                                    "arg1", "arg2", "delimiter", "message", "string", "substring",
2108                                    "value"
2109                    });
2110            private static final List<String> _allowedVarAttributes =
2111                    ListUtil.fromArray(
2112                            new String[] {
2113                                    "attribute", "group", "input", "line-number", "locator",
2114                                    "locator-key", "method", "name", "path", "pattern",
2115                                    "property-value", "value"
2116                    });
2117            private static final List<String> _methodNames = ListUtil.fromArray(
2118                    new String[] {
2119                            "getFirstNumber", "getIPAddress", "increment", "length",
2120                            "lowercase", "replace", "uppercase"
2121                    });
2122            private static final List<String> _reservedTags = ListUtil.fromArray(
2123                    new String[] {
2124                            "and", "case", "command", "condition", "contains", "default",
2125                            "definition", "delimiter", "description", "echo", "else", "elseif",
2126                            "equals", "execute", "fail", "for", "if", "isset", "not", "or",
2127                            "property", "set-up", "take-screenshot", "task", "td", "tear-down",
2128                            "then", "tr", "while", "var"
2129                    });
2130    
2131            private final String _baseDirName;
2132            private final List<String> _componentNames;
2133            private final Pattern _pathTrElementStatementPattern = Pattern.compile(
2134                    "[A-Z0-9].*");
2135            private final Pattern _pathTrElementWordPattern1 = Pattern.compile(
2136                    "[A-Za-z0-9\\-]+");
2137            private final Pattern _pathTrElementWordPattern2 = Pattern.compile(
2138                    "[A-Z0-9][A-Za-z0-9\\-]*");
2139            private final Pattern _tagPattern = Pattern.compile("<[a-z\\-]+");
2140            private final List<String> _testCaseAvailablePropertyNames;
2141            private final List<String> _testrayAvailableComponentNames;
2142            private final Pattern _varElementFunctionPattern = Pattern.compile(
2143                    "\\$\\{(locator|value)[0-9]+\\}");
2144            private final Pattern _varElementPattern = Pattern.compile(
2145                    "\\$\\{([^\\}]*?)\\}");
2146            private final Pattern _varElementStatementPattern = Pattern.compile(
2147                    "(.*)\\?(.*)\\(([^\\)]*?)\\)");
2148    
2149    }