All files / types/__testUtils__ testMembers.ts

100% Statements 25/25
100% Branches 1/1
100% Functions 5/5
100% Lines 25/25

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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133                                                                                54x                                 6x 6x 6x 14x 14x                 6x                   6x 6x 6x 9x 9x           6x             11x 11x 11x 19x 19x           11x                   10x 10x 10x 12x 12x           10x          
import type IBitmapFieldLayout from "../IBitmapFieldLayout";
import type IBitmapFieldSymbol from "../symbols/IBitmapFieldSymbol";
import type IRegisterMemberSymbol from "../symbols/IRegisterMemberSymbol";
import type IEnumMemberSymbol from "../symbols/IEnumMemberSymbol";
import type IStructFieldSymbol from "../symbols/IStructFieldSymbol";
import type TSymbolKindCNext from "../symbol-kinds/TSymbolKindCNext";
import ESourceLanguage from "../../utils/types/ESourceLanguage";
import ScopeUtils from "../../utils/ScopeUtils";
import TestSourceSpan from "./testSourceSpan";
 
/**
 * Lifts the plain member records mocks used to write into member SYMBOLS.
 *
 * Struct fields, bitmap fields and register members became symbols in #1318,
 * so each one a mock builds now needs nine more fields. These helpers WRAP the
 * existing literal rather than replacing it, so a test that was about header
 * emission stays about header emission instead of turning into a test about
 * symbol identity.
 *
 * Identity comes from `ScopeUtils.identityOf` -- the same encoder
 * `MemberSymbolBase` uses in production -- so a mock cannot assert a key the
 * real collector would never produce. Spans are distinct per member, so a test
 * claiming a member reports its OWN position cannot pass by coincidence.
 */
class TestMembers {
  /**
   * The nine `IBaseSymbol` fields a member mock needs.
   *
   * Public because `testEnumMembers` builds the same nine and used to hand-copy
   * them (#1318 review) -- the duplication `MemberSymbolBase` exists to prevent
   * on the production side, reintroduced on the mock side, where a tenth field
   * on `IBaseSymbol` would have meant editing both and the two would have
   * drifted silently because different tests exercise each.
   */
  static base(
    kind: TSymbolKindCNext,
    name: string,
    ownerScopedName: string,
    line: number,
  ) {
    return {
      kind,
      name,
      scopePath: ownerScopedName,
      ...ScopeUtils.identityOf({ name, scopePath: ownerScopedName }),
      sourceFile: "test.cnx",
      span: TestSourceSpan.at(line),
      sourceLanguage: ESourceLanguage.CNext,
      visibility: "public" as const,
    };
  }
 
  static asEnumMembers(
    enumScopedName: string,
    values: Readonly<Record<string, number>>,
    sourceFile = "test.cnx",
  ): Map<string, IEnumMemberSymbol> {
    const members = new Map<string, IEnumMemberSymbol>();
    let line = 1;
    for (const [name, value] of Object.entries(values)) {
      line += 1;
      members.set(name, {
        ...TestMembers.base("enum_member", name, enumScopedName, line),
        sourceFile,
        kind: "enum_member",
        // A test states the settled value; the value as written is not its subject
        valueExpr: null,
        value,
      });
    }
    return members;
  }
 
  static asStructFields(
    ownerScopedName: string,
    fields: ReadonlyMap<
      string,
      Omit<IStructFieldSymbol, keyof ReturnType<typeof TestMembers.base>>
    >,
  ): Map<string, IStructFieldSymbol> {
    const out = new Map<string, IStructFieldSymbol>();
    let line = 1;
    for (const [name, rest] of fields) {
      line += 1;
      out.set(name, {
        ...TestMembers.base("struct_field", name, ownerScopedName, line),
        ...rest,
        kind: "struct_field",
      });
    }
    return out;
  }
 
  static asBitmapFields(
    ownerScopedName: string,
    fields: ReadonlyMap<string, IBitmapFieldLayout>,
  ): Map<string, IBitmapFieldSymbol> {
    const out = new Map<string, IBitmapFieldSymbol>();
    let line = 1;
    for (const [name, rest] of fields) {
      line += 1;
      out.set(name, {
        ...TestMembers.base("bitmap_field", name, ownerScopedName, line),
        ...rest,
        kind: "bitmap_field",
      });
    }
    return out;
  }
 
  static asRegisterMembers(
    ownerScopedName: string,
    members: ReadonlyMap<
      string,
      Omit<IRegisterMemberSymbol, keyof ReturnType<typeof TestMembers.base>>
    >,
  ): Map<string, IRegisterMemberSymbol> {
    const out = new Map<string, IRegisterMemberSymbol>();
    let line = 1;
    for (const [name, rest] of members) {
      line += 1;
      out.set(name, {
        ...TestMembers.base("register_member", name, ownerScopedName, line),
        ...rest,
        kind: "register_member",
      });
    }
    return out;
  }
}
 
export default TestMembers;