All files / src/rules add_test_attributes.ts

96.11% Statements 99/103
75% Branches 18/24
100% Functions 5/5
96.11% Lines 99/103

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 1041x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 12080x 12080x 12080x 12080x 12080x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 36094x 12080x 12080x 11539x 11539x 12080x 12080x 255x 255x 12080x 12080x 276x 276x 276x 276x 12x 12x 264x 276x 134x 134x     134x 134x 134x 131x 131x 3x 134x 134x 134x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 134x     1x 1x 1x 1x 1x 1x 1x 134x 264x 264x 264x 12080x 12080x  
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import * as Statements from "../abap/2_statements/statements";
import * as Structures from "../abap/3_structures/structures";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
 
export class AddTestAttributesConf extends BasicRuleConfig {
}
 
export class AddTestAttributes extends ABAPRule {
 
  private conf = new AddTestAttributesConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "add_test_attributes",
      title: "Add test attributes for tests classes with test methods",
      shortDescription: `Add test attributes DURATION and RISK LEVEL for tests classes with test methods`,
      tags: [RuleTag.SingleFile],
      badExample: `CLASS ltcl_test1 DEFINITION FINAL FOR TESTING.
  PUBLIC SECTION.
  PROTECTED SECTION.
  PRIVATE SECTION.
    METHODS test FOR TESTING RAISING cx_static_check.
ENDCLASS.
 
CLASS ltcl_test1 IMPLEMENTATION.
  METHOD test.
  ENDMETHOD.
ENDCLASS.`,
      goodExample: `CLASS ltcl_test2 DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
  PUBLIC SECTION.
  PROTECTED SECTION.
  PRIVATE SECTION.
    METHODS test FOR TESTING RAISING cx_static_check.
ENDCLASS.
 
CLASS ltcl_test2 IMPLEMENTATION.
  METHOD test.
  ENDMETHOD.
ENDCLASS.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: AddTestAttributesConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
 
    const stru = file.getStructure();
    if (stru === undefined) {
      return [];
    }
 
    for (const classStructure of stru.findAllStructures(Structures.ClassDefinition)) {
      const cdef = classStructure.findFirstStatement(Statements.ClassDefinition);
      if (cdef === undefined) {
        continue;
      }
 
      const cdefConcat = cdef?.concatTokens().toUpperCase();
      if (cdefConcat?.includes(" FOR TESTING") === false) {
        continue;
      }
 
      const hasDuration = cdefConcat?.includes(" DURATION ");
      const hasRiskLevel = cdefConcat?.includes(" RISK LEVEL ");
      if (hasDuration === true && hasRiskLevel === true) {
        continue;
      }
 
      let hasTestMethod = false;
      for (const mdef of classStructure.findAllStatements(Statements.MethodDef)) {
        const concat = mdef.concatTokens().toUpperCase();
        if (concat.includes(" FOR TESTING")) {
          hasTestMethod = true;
        }
      }
 
      if (hasTestMethod === false) {
        continue;
      }
 
      if (hasDuration === false) {
        issues.push(Issue.atStatement(file, cdef, "Add DURATION", this.getMetadata().key, this.getConfig().severity));
      }
      if (hasRiskLevel === false) {
        issues.push(Issue.atStatement(file, cdef, "Add RISK LEVEL", this.getMetadata().key, this.getConfig().severity));
      }
    }
 
    return issues;
  }
 
}