Files
capa/web/explorer/src/tests/rdocParser.test.js
Ana Maria Martinez Gomez df7697db84 [copyright + license] Add missing headers
Add copyright and license information headers to the source code files
inside the `web` directory and the `capa/render/proto/capa.proto` file.
I have used addlicense to add the headers.
2025-01-15 08:52:42 -07:00

303 lines
11 KiB
JavaScript

/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { describe, it, expect } from "vitest";
import { parseRules, parseFunctionCapabilities } from "../utils/rdocParser";
describe("parseRules", () => {
it("should return an empty array for empty rules", () => {
const rules = {};
const flavor = "static";
const layout = {};
const result = parseRules(rules, flavor, layout);
expect(result).toEqual([]);
});
it("should correctly parse a simple rule with static scope", () => {
const rules = {
"test rule": {
meta: {
name: "test rule",
namespace: "test",
lib: false,
scopes: {
static: "function",
dynamic: "process"
}
},
source: "test rule source",
matches: [
[
{ type: "absolute", value: 0x1000 },
{
success: true,
node: { type: "feature", feature: { type: "api", api: "TestAPI" } },
children: [],
locations: [{ type: "absolute", value: 0x1000 }],
captures: {}
}
]
]
}
};
const result = parseRules(rules, "static", {});
expect(result).toHaveLength(1);
expect(result[0].key).toBe("0");
expect(result[0].data.type).toBe("rule");
expect(result[0].data.name).toBe("test rule");
expect(result[0].data.lib).toBe(false);
expect(result[0].data.namespace).toBe("test");
expect(result[0].data.source).toBe("test rule source");
expect(result[0].children).toHaveLength(1);
expect(result[0].children[0].key).toBe("0-0");
expect(result[0].children[0].data.type).toBe("match location");
expect(result[0].children[0].children[0].data.type).toBe("feature");
expect(result[0].children[0].children[0].data.typeValue).toBe("api");
expect(result[0].children[0].children[0].data.name).toBe("TestAPI");
});
it('should handle rule with "not" statements correctly', () => {
const rules = {
"test rule": {
meta: {
name: "test rule",
namespace: "test",
lib: false,
scopes: {
static: "function",
dynamic: "process"
}
},
source: "test rule source",
matches: [
[
{ type: "absolute", value: 0x1000 },
{
success: true,
node: { type: "statement", statement: { type: "not" } },
children: [
{ success: false, node: { type: "feature", feature: { type: "api", api: "TestAPI" } } }
]
}
]
]
}
};
const result = parseRules(rules, "static", {});
expect(result).toHaveLength(1);
expect(result[0].children[0].children[0].data.type).toBe("statement");
expect(result[0].children[0].children[0].data.name).toBe("not:");
expect(result[0].children[0].children[0].children[0].data.type).toBe("feature");
expect(result[0].children[0].children[0].children[0].data.typeValue).toBe("api");
expect(result[0].children[0].children[0].children[0].data.name).toBe("TestAPI");
});
});
describe("parseFunctionCapabilities", () => {
it("should return an empty array when no functions match", () => {
const mockData = {
meta: {
analysis: {
feature_counts: {
file: 0,
functions: []
},
layout: {
functions: []
}
}
},
rules: {}
};
const result = parseFunctionCapabilities(mockData, false);
expect(result).toEqual([]);
});
it("should parse a single function with one rule match", () => {
const mockDoc = {
meta: {
analysis: {
layout: {
functions: [
{
address: { type: "absolute", value: 0x1000 },
matched_basic_blocks: [{ address: { type: "absolute", value: 0x1000 } }]
}
]
},
feature_counts: {
functions: [{ address: { type: "absolute", value: 0x1000 } }]
}
}
},
rules: {
rule1: {
meta: {
name: "Test Rule",
namespace: "test",
lib: false,
scopes: { static: "function" }
},
matches: [[{ type: "absolute", value: 0x1000 }]]
}
}
};
const result = parseFunctionCapabilities(mockDoc);
expect(result).toEqual([
{
address: "0x1000",
capabilities: [{ name: "Test Rule", namespace: "test", lib: false }]
}
]);
});
it("should handle multiple rules matching a single function", () => {
const mockDoc = {
meta: {
analysis: {
layout: {
functions: [
{
address: { type: "absolute", value: 0x1000 },
matched_basic_blocks: [{ address: { type: "absolute", value: 0x1000 } }]
}
]
},
feature_counts: {
functions: [{ address: { type: "absolute", value: 0x1000 } }]
}
}
},
rules: {
rule1: {
meta: {
name: "Test Rule 1",
lib: true,
scopes: { static: "function" }
},
matches: [[{ type: "absolute", value: 0x1000 }]]
},
rule2: {
meta: {
name: "Test Rule 2",
namespace: "test",
lib: false,
scopes: { static: "function" }
},
matches: [[{ type: "absolute", value: 0x1000 }]]
}
}
};
const result = parseFunctionCapabilities(mockDoc);
expect(result).toEqual([
{
address: "0x1000",
capabilities: [
{ name: "Test Rule 1", lib: true },
{ name: "Test Rule 2", namespace: "test", lib: false }
]
}
]);
});
it("should handle basic block scoped rules", () => {
const mockDoc = {
meta: {
analysis: {
layout: {
functions: [
{
address: { type: "absolute", value: 0x1000 },
matched_basic_blocks: [{ address: { type: "absolute", value: 0x1100 } }]
}
]
},
feature_counts: {
functions: [{ address: { type: "absolute", value: 0x1000 } }]
}
}
},
rules: {
rule1: {
meta: {
name: "Basic Block Rule",
namespace: "test",
lib: false,
scopes: { static: "basic block" }
},
matches: [[{ type: "absolute", value: 0x1100 }]]
}
}
};
const result = parseFunctionCapabilities(mockDoc);
expect(result).toEqual([
{
address: "0x1000",
capabilities: [{ name: "Basic Block Rule", namespace: "test", lib: false }]
}
]);
});
it("should handle a single rule matching in multiple functions", () => {
const mockDoc = {
meta: {
analysis: {
layout: {
functions: [
{
address: { type: "absolute", value: 0x1000 },
matched_basic_blocks: [{ address: { type: "absolute", value: 0x1000 } }]
},
{
address: { type: "absolute", value: 0x2000 },
matched_basic_blocks: [{ address: { type: "absolute", value: 0x2000 } }]
}
]
},
feature_counts: {
functions: [
{ address: { type: "absolute", value: 0x1000 } },
{ address: { type: "absolute", value: 0x2000 } }
]
}
}
},
rules: {
rule1: {
meta: {
name: "Test Rule",
namespace: "test",
lib: false,
scopes: { static: "function" }
},
matches: [[{ type: "absolute", value: 0x1000 }], [{ type: "absolute", value: 0x2000 }]]
}
}
};
const result = parseFunctionCapabilities(mockDoc);
expect(result).toEqual([
{
address: "0x1000",
capabilities: [{ name: "Test Rule", namespace: "test", lib: false }]
},
{
address: "0x2000",
capabilities: [{ name: "Test Rule", namespace: "test", lib: false }]
}
]);
});
});