Files
theia-code-os/packages/ai-chat/src/common/chat-model-serialization.spec.ts
mawkone 8bb5110148
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled
deploy: current vibn theia state
Made-with: Cursor
2026-02-27 12:01:08 -08:00

671 lines
31 KiB
TypeScript

// *****************************************************************************
// Copyright (C) 2025 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { expect } from 'chai';
import { ChatAgentLocation } from './chat-agents';
import { MutableChatModel } from './chat-model';
import { ParsedChatRequest, ParsedChatRequestTextPart, ParsedChatRequestVariablePart, ParsedChatRequestFunctionPart, ParsedChatRequestAgentPart } from './parsed-chat-request';
import { ToolRequest } from '@theia/ai-core';
import { SerializableTextPart, SerializableVariablePart, SerializableFunctionPart, SerializableAgentPart } from './chat-model-serialization';
describe('ChatModel Serialization and Restoration', () => {
function createParsedRequest(text: string): ParsedChatRequest {
return {
request: { text },
parts: [
new ParsedChatRequestTextPart(
{ start: 0, endExclusive: text.length },
text
)
],
toolRequests: new Map(),
variables: []
};
}
describe('Simple tree serialization', () => {
it('should serialize a chat with a single request', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
model.addRequest(createParsedRequest('Hello'));
const serialized = model.toSerializable();
expect(serialized.hierarchy).to.be.an('object');
expect(serialized.hierarchy!.rootBranchId).to.be.a('string');
expect(serialized.hierarchy!.branches).to.be.an('object');
expect(serialized.requests).to.have.lengthOf(1);
expect(serialized.requests[0].text).to.equal('Hello');
});
it('should serialize a chat with multiple sequential requests', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
model.addRequest(createParsedRequest('First'));
model.addRequest(createParsedRequest('Second'));
model.addRequest(createParsedRequest('Third'));
const serialized = model.toSerializable();
expect(serialized.hierarchy).to.be.an('object');
expect(serialized.requests).to.have.lengthOf(3);
// Verify the hierarchy has 3 branches (one for each request)
const branches = Object.values(serialized.hierarchy!.branches);
expect(branches).to.have.lengthOf(3);
// Verify the active path through the tree
const rootBranch = serialized.hierarchy!.branches[serialized.hierarchy!.rootBranchId];
expect(rootBranch.items).to.have.lengthOf(1);
expect(rootBranch.items[0].requestId).to.equal(serialized.requests[0].id);
expect(rootBranch.items[0].nextBranchId).to.be.a('string');
});
});
describe('Tree serialization with alternatives (edited messages)', () => {
it('should serialize a chat with edited messages', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
// Add first request
const req1 = model.addRequest(createParsedRequest('Original message'));
req1.response.complete();
// Add second request
model.addRequest(createParsedRequest('Follow-up'));
// Edit the first request (creating an alternative)
const branch1 = model.getBranch(req1.id);
expect(branch1).to.not.be.undefined;
branch1!.add(model.addRequest(createParsedRequest('Edited message'), 'agent-1'));
const serialized = model.toSerializable();
// Should have 3 requests: original, edited, and follow-up
expect(serialized.requests).to.have.lengthOf(3);
// The root branch should have 2 items (original and edited alternatives)
const rootBranch = serialized.hierarchy!.branches[serialized.hierarchy!.rootBranchId];
expect(rootBranch.items).to.have.lengthOf(2);
expect(rootBranch.items[0].requestId).to.equal(serialized.requests[0].id);
expect(rootBranch.items[1].requestId).to.equal(serialized.requests[2].id);
// The active branch index should point to the most recent alternative
expect(rootBranch.activeBranchIndex).to.be.at.least(0);
});
it('should serialize nested alternatives (edited multiple times)', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
// Add first request
const req1 = model.addRequest(createParsedRequest('First'));
req1.response.complete();
// Add second request
const req2 = model.addRequest(createParsedRequest('Second'));
req2.response.complete();
// Edit the second request (creating an alternative)
const branch2 = model.getBranch(req2.id);
expect(branch2).to.not.be.undefined;
const req2edited = model.addRequest(createParsedRequest('Second (edited)'), 'agent-1');
branch2!.add(req2edited);
// Add third request after the edited version
model.addRequest(createParsedRequest('Third'));
const serialized = model.toSerializable();
// Should have 4 requests total
expect(serialized.requests).to.have.lengthOf(4);
// Find the second-level branch
const rootBranch = serialized.hierarchy!.branches[serialized.hierarchy!.rootBranchId];
const nextBranchId = rootBranch.items[rootBranch.activeBranchIndex].nextBranchId;
expect(nextBranchId).to.be.a('string');
const secondBranch = serialized.hierarchy!.branches[nextBranchId!];
expect(secondBranch.items).to.have.lengthOf(2); // Original and edited
});
});
describe('Tree restoration from serialized data', () => {
it('should restore a simple chat session', () => {
// Create and serialize
const model1 = new MutableChatModel(ChatAgentLocation.Panel);
model1.addRequest(createParsedRequest('Hello'));
const serialized = model1.toSerializable();
// Restore
const model2 = new MutableChatModel(serialized);
expect(model2.getRequests()).to.have.lengthOf(1);
expect(model2.getRequests()[0].request.text).to.equal('Hello');
});
it('should restore chat with multiple sequential requests', () => {
// Create and serialize
const model1 = new MutableChatModel(ChatAgentLocation.Panel);
model1.addRequest(createParsedRequest('First'));
model1.addRequest(createParsedRequest('Second'));
model1.addRequest(createParsedRequest('Third'));
const serialized = model1.toSerializable();
// Restore
const model2 = new MutableChatModel(serialized);
const requests = model2.getRequests();
expect(requests).to.have.lengthOf(3);
expect(requests[0].request.text).to.equal('First');
expect(requests[1].request.text).to.equal('Second');
expect(requests[2].request.text).to.equal('Third');
});
it('should restore chat with edited messages (alternatives)', () => {
// Create and serialize
const model1 = new MutableChatModel(ChatAgentLocation.Panel);
const req1 = model1.addRequest(createParsedRequest('Original'));
req1.response.complete();
const branch1 = model1.getBranch(req1.id);
const req1edited = model1.addRequest(createParsedRequest('Edited'), 'agent-1');
branch1!.add(req1edited);
const serialized = model1.toSerializable();
// Verify serialization includes both alternatives
expect(serialized.requests).to.have.lengthOf(2);
// Restore
const model2 = new MutableChatModel(serialized);
// Check that both alternatives are restored
const restoredBranch = model2.getBranch(serialized.requests[0].id);
expect(restoredBranch).to.not.be.undefined;
expect(restoredBranch!.items).to.have.lengthOf(2);
expect(restoredBranch!.items[0].element.request.text).to.equal('Original');
expect(restoredBranch!.items[1].element.request.text).to.equal('Edited');
});
it('should restore the correct active branch indices', () => {
// Create and serialize
const model1 = new MutableChatModel(ChatAgentLocation.Panel);
const req1 = model1.addRequest(createParsedRequest('Original'));
req1.response.complete();
const branch1 = model1.getBranch(req1.id);
const req1edited = model1.addRequest(createParsedRequest('Edited'), 'agent-1');
branch1!.add(req1edited);
// Switch to the edited version
branch1!.enable(req1edited);
const activeBranchIndex1 = branch1!.activeBranchIndex;
const serialized = model1.toSerializable();
// Restore
const model2 = new MutableChatModel(serialized);
const restoredBranch = model2.getBranch(serialized.requests[0].id);
expect(restoredBranch).to.not.be.undefined;
expect(restoredBranch!.activeBranchIndex).to.equal(activeBranchIndex1);
});
it('should restore a simple session with hierarchy', () => {
// Create serialized data with hierarchy
const serializedData = {
sessionId: 'simple-session',
location: ChatAgentLocation.Panel,
hierarchy: {
rootBranchId: 'branch-root',
branches: {
'branch-root': {
id: 'branch-root',
items: [{ requestId: 'request-1' }],
activeBranchIndex: 0
}
}
},
requests: [
{
id: 'request-1',
text: 'Hello'
}
],
responses: [
{
id: 'response-1',
requestId: 'request-1',
isComplete: true,
isError: false,
content: []
}
]
};
// Should restore without errors
const model = new MutableChatModel(serializedData);
expect(model.getRequests()).to.have.lengthOf(1);
expect(model.getRequests()[0].request.text).to.equal('Hello');
});
});
describe('Complete round-trip with complex tree', () => {
it('should serialize and restore a complex tree structure', () => {
// Create a complex chat with multiple edits
const model1 = new MutableChatModel(ChatAgentLocation.Panel);
// Level 1
const req1 = model1.addRequest(createParsedRequest('Level 1 - Original'));
req1.response.complete();
// Level 2
const req2 = model1.addRequest(createParsedRequest('Level 2 - Original'));
req2.response.complete();
// Edit Level 1
const branch1 = model1.getBranch(req1.id);
const req1edited = model1.addRequest(createParsedRequest('Level 1 - Edited'), 'agent-1');
branch1!.add(req1edited);
// Add Level 2 alternative after edited Level 1
const req2alt = model1.addRequest(createParsedRequest('Level 2 - Alternative'));
req2alt.response.complete();
// Edit Level 2 alternative
const branch2alt = model1.getBranch(req2alt.id);
const req2altEdited = model1.addRequest(createParsedRequest('Level 2 - Alternative Edited'), 'agent-1');
branch2alt!.add(req2altEdited);
const serialized = model1.toSerializable();
// Verify serialization
expect(serialized.requests).to.have.lengthOf(5);
expect(serialized.hierarchy).to.be.an('object');
// Restore
const model2 = new MutableChatModel(serialized);
// Verify all requests are present
const allRequests = model2.getAllRequests();
expect(allRequests).to.have.lengthOf(5);
// Verify branch structure
const restoredBranch1 = model2.getBranches()[0];
expect(restoredBranch1.items).to.have.lengthOf(2); // Original + Edited
// Verify we can navigate the alternatives
expect(restoredBranch1.items[0].element.request.text).to.equal('Level 1 - Original');
expect(restoredBranch1.items[1].element.request.text).to.equal('Level 1 - Edited');
});
it('should preserve all requests across multiple serialization/restoration cycles', () => {
// Create initial model
let model = new MutableChatModel(ChatAgentLocation.Panel);
const req1 = model.addRequest(createParsedRequest('Request 1'));
req1.response.complete();
// Cycle 1
let serialized = model.toSerializable();
model = new MutableChatModel(serialized);
// Add more requests
model.addRequest(createParsedRequest('Request 2'));
// Cycle 2
serialized = model.toSerializable();
model = new MutableChatModel(serialized);
// Add an edit
const branch = model.getBranches()[0];
const reqEdited = model.addRequest(createParsedRequest('Request 1 - Edited'), 'agent-1');
branch.add(reqEdited);
// Final cycle
serialized = model.toSerializable();
const finalModel = new MutableChatModel(serialized);
// Verify all requests are preserved
expect(finalModel.getBranches()[0].items).to.have.lengthOf(2);
const allRequests = finalModel.getAllRequests();
expect(allRequests).to.have.lengthOf(3);
});
});
describe('ParsedChatRequest serialization', () => {
it('should serialize and restore a simple text request', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
model.addRequest(createParsedRequest('Hello world'));
const serialized = model.toSerializable();
expect(serialized.requests[0].parsedRequest).to.not.be.undefined;
expect(serialized.requests[0].parsedRequest!.parts).to.have.lengthOf(1);
expect(serialized.requests[0].parsedRequest!.parts[0].kind).to.equal('text');
const textPart = serialized.requests[0].parsedRequest!.parts[0] as SerializableTextPart;
expect(textPart.text).to.equal('Hello world');
const restored = new MutableChatModel(serialized);
const restoredRequest = restored.getRequests()[0];
expect(restoredRequest.message.parts).to.have.lengthOf(1);
expect(restoredRequest.message.parts[0].kind).to.equal('text');
expect(restoredRequest.message.parts[0].text).to.equal('Hello world');
});
it('should serialize and restore a request with variable references', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
const parsedRequest: ParsedChatRequest = {
request: { text: 'Use #file and #selection' },
parts: [
new ParsedChatRequestTextPart({ start: 0, endExclusive: 4 }, 'Use '),
(() => {
const variablePart = new ParsedChatRequestVariablePart(
{ start: 4, endExclusive: 9 },
'file',
undefined
);
variablePart.resolution = {
variable: { id: 'file-var', name: 'file', description: 'Current file' },
value: 'file content here'
};
return variablePart;
})(),
new ParsedChatRequestTextPart({ start: 9, endExclusive: 14 }, ' and '),
(() => {
const variablePart = new ParsedChatRequestVariablePart(
{ start: 14, endExclusive: 24 },
'selection',
undefined
);
variablePart.resolution = {
variable: { id: 'sel-var', name: 'selection', description: 'Selected text' },
value: 'selected text'
};
return variablePart;
})()
],
toolRequests: new Map(),
variables: [
{
variable: { id: 'file-var', name: 'file', description: 'Current file' },
value: 'file content here'
},
{
variable: { id: 'sel-var', name: 'selection', description: 'Selected text' },
value: 'selected text'
}
]
};
model.addRequest(parsedRequest);
const serialized = model.toSerializable();
expect(serialized.requests[0].parsedRequest).to.not.be.undefined;
expect(serialized.requests[0].parsedRequest!.parts).to.have.lengthOf(4);
expect(serialized.requests[0].parsedRequest!.parts[1].kind).to.equal('var');
const varPart1 = serialized.requests[0].parsedRequest!.parts[1] as SerializableVariablePart;
expect(varPart1.variableId).to.equal('file-var');
expect(varPart1.variableName).to.equal('file');
expect(varPart1.variableValue).to.equal('file content here');
expect(varPart1.variableDescription).to.equal('Current file');
expect(serialized.requests[0].parsedRequest!.variables).to.have.lengthOf(2);
const restored = new MutableChatModel(serialized);
const restoredRequest = restored.getRequests()[0];
expect(restoredRequest.message.parts).to.have.lengthOf(4);
expect(restoredRequest.message.parts[1].kind).to.equal('var');
const varPart = restoredRequest.message.parts[1] as ParsedChatRequestVariablePart;
expect(varPart.variableName).to.equal('file');
expect(varPart.resolution?.variable.id).to.equal('file-var');
expect(varPart.resolution?.value).to.equal('file content here');
expect(restoredRequest.message.variables).to.have.lengthOf(2);
expect(restoredRequest.message.variables[0].value).to.equal('file content here');
expect(varPart.resolution?.variable.description).to.equal('Current file');
});
it('should serialize and restore a request with agent references', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
const parsedRequest: ParsedChatRequest = {
request: { text: '@codeAgent help me' },
parts: [
new ParsedChatRequestAgentPart(
{ start: 0, endExclusive: 10 },
'code-agent-id',
'codeAgent'
),
new ParsedChatRequestTextPart({ start: 10, endExclusive: 19 }, ' help me')
],
toolRequests: new Map(),
variables: []
};
model.addRequest(parsedRequest, 'code-agent-id');
const serialized = model.toSerializable();
expect(serialized.requests[0].parsedRequest).to.not.be.undefined;
expect(serialized.requests[0].parsedRequest!.parts[0].kind).to.equal('agent');
const agentPart1 = serialized.requests[0].parsedRequest!.parts[0] as SerializableAgentPart;
expect(agentPart1.agentId).to.equal('code-agent-id');
expect(agentPart1.agentName).to.equal('codeAgent');
const restored = new MutableChatModel(serialized);
const restoredRequest = restored.getRequests()[0];
expect(restoredRequest.message.parts[0].kind).to.equal('agent');
const agentPart = restoredRequest.message.parts[0] as ParsedChatRequestAgentPart;
expect(agentPart.agentId).to.equal('code-agent-id');
expect(agentPart.agentName).to.equal('codeAgent');
});
it('should serialize and restore a request with tool requests', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
const toolRequest: ToolRequest = {
id: 'tool-1',
name: 'search',
description: 'Search the web',
parameters: {
type: 'object',
properties: {
query: { type: 'string' }
},
required: ['query']
},
handler: async () => 'search results'
};
const parsedRequest: ParsedChatRequest = {
request: { text: 'Search for ~tool-1' },
parts: [
new ParsedChatRequestTextPart({ start: 0, endExclusive: 11 }, 'Search for '),
new ParsedChatRequestFunctionPart({ start: 11, endExclusive: 18 }, toolRequest)
],
toolRequests: new Map([['tool-1', toolRequest]]),
variables: []
};
model.addRequest(parsedRequest);
const serialized = model.toSerializable();
expect(serialized.requests[0].parsedRequest).to.not.be.undefined;
expect(serialized.requests[0].parsedRequest!.parts[1].kind).to.equal('function');
const funcPart1 = serialized.requests[0].parsedRequest!.parts[1] as SerializableFunctionPart;
expect(funcPart1.toolRequestId).to.equal('tool-1');
expect(serialized.requests[0].parsedRequest!.toolRequests).to.have.lengthOf(1);
expect(serialized.requests[0].parsedRequest!.toolRequests[0].id).to.equal('tool-1');
const restored = new MutableChatModel(serialized);
const restoredRequest = restored.getRequests()[0];
expect(restoredRequest.message.parts[1].kind).to.equal('function');
const funcPart = restoredRequest.message.parts[1] as ParsedChatRequestFunctionPart;
expect(funcPart.toolRequest.id).to.equal('tool-1');
expect(restoredRequest.message.toolRequests.size).to.equal(1);
expect(restoredRequest.message.toolRequests.get('tool-1')).to.not.be.undefined;
});
it('should handle complex mixed requests with all part types', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
const toolRequest: ToolRequest = {
id: 'analyze-tool',
name: 'analyze',
parameters: { type: 'object', properties: {} },
handler: async () => 'analysis'
};
const parsedRequest: ParsedChatRequest = {
request: { text: '@agent analyze #file using ~analyze-tool' },
parts: [
new ParsedChatRequestAgentPart({ start: 0, endExclusive: 6 }, 'agent-1', 'agent'),
new ParsedChatRequestTextPart({ start: 6, endExclusive: 15 }, ' analyze '),
(() => {
const varPart = new ParsedChatRequestVariablePart({ start: 15, endExclusive: 20 }, 'file', undefined);
varPart.resolution = {
variable: { id: 'f', name: 'file', description: 'File' },
value: 'code.ts'
};
return varPart;
})(),
new ParsedChatRequestTextPart({ start: 20, endExclusive: 27 }, ' using '),
new ParsedChatRequestFunctionPart({ start: 27, endExclusive: 41 }, toolRequest)
],
toolRequests: new Map([['analyze-tool', toolRequest]]),
variables: [{ variable: { id: 'f', name: 'file', description: 'File' }, value: 'code.ts' }]
};
model.addRequest(parsedRequest, 'agent-1');
const serialized = model.toSerializable();
const parsedReqData = serialized.requests[0].parsedRequest!;
expect(parsedReqData.parts).to.have.lengthOf(5);
expect(parsedReqData.parts[0].kind).to.equal('agent');
expect(parsedReqData.parts[2].kind).to.equal('var');
expect(parsedReqData.parts[4].kind).to.equal('function');
const restored = new MutableChatModel(serialized);
const restoredMsg = restored.getRequests()[0].message;
expect(restoredMsg.parts).to.have.lengthOf(5);
expect(restoredMsg.parts[0].kind).to.equal('agent');
expect(restoredMsg.parts[2].kind).to.equal('var');
expect(restoredMsg.parts[4].kind).to.equal('function');
expect(restoredMsg.toolRequests.size).to.equal(1);
expect(restoredMsg.variables).to.have.lengthOf(1);
});
it('should handle fallback for requests without parsedRequest data', () => {
const serializedData = {
sessionId: 'test-session',
location: ChatAgentLocation.Panel,
hierarchy: {
rootBranchId: 'root',
branches: {
'root': {
id: 'root',
items: [{ requestId: 'req-1' }],
activeBranchIndex: 0
}
}
},
requests: [
{
id: 'req-1',
text: 'Plain text without parsed data'
}
],
responses: []
};
const model = new MutableChatModel(serializedData);
const request = model.getRequests()[0];
expect(request.message.parts).to.have.lengthOf(1);
expect(request.message.parts[0].kind).to.equal('text');
expect(request.message.parts[0].text).to.equal('Plain text without parsed data');
});
it('should create placeholder tool requests during deserialization', async () => {
const toolRequest: ToolRequest = {
id: 'my-tool',
name: 'myTool',
description: 'My test tool',
parameters: {
type: 'object',
properties: {
query: { type: 'string' }
},
required: ['query']
},
handler: async () => 'tool result'
};
const model = new MutableChatModel(ChatAgentLocation.Panel);
const parsedRequest: ParsedChatRequest = {
request: { text: 'Use ~my-tool' },
parts: [
new ParsedChatRequestTextPart({ start: 0, endExclusive: 4 }, 'Use '),
new ParsedChatRequestFunctionPart({ start: 4, endExclusive: 12 }, toolRequest)
],
toolRequests: new Map([['my-tool', toolRequest]]),
variables: []
};
model.addRequest(parsedRequest);
const serialized = model.toSerializable();
expect(serialized.requests[0].parsedRequest).to.not.be.undefined;
expect(serialized.requests[0].parsedRequest!.toolRequests).to.have.lengthOf(1);
expect(serialized.requests[0].parsedRequest!.toolRequests[0].id).to.equal('my-tool');
const restored = new MutableChatModel(serialized);
const restoredRequest = restored.getRequests()[0];
// Verify placeholder was created
expect(restoredRequest.message.parts[1].kind).to.equal('function');
const funcPart = restoredRequest.message.parts[1] as ParsedChatRequestFunctionPart;
expect(funcPart.toolRequest.id).to.equal('my-tool');
// Verify it's a placeholder (handler should throw about not being restored)
try {
await funcPart.toolRequest.handler('test-input');
expect.fail('Should have thrown');
} catch (error) {
expect((error as Error).message).to.include('not yet restored');
}
});
it('should preserve variable arguments during serialization', () => {
const model = new MutableChatModel(ChatAgentLocation.Panel);
const varPartWithArg = new ParsedChatRequestVariablePart(
{ start: 0, endExclusive: 10 },
'file',
'main.ts'
);
varPartWithArg.resolution = {
variable: { id: 'f', name: 'file', description: 'File variable' },
arg: 'main.ts',
value: 'file content of main.ts'
};
const parsedRequest: ParsedChatRequest = {
request: { text: '#file:main.ts' },
parts: [varPartWithArg],
toolRequests: new Map(),
variables: [varPartWithArg.resolution]
};
model.addRequest(parsedRequest);
const serialized = model.toSerializable();
const serializedVar = serialized.requests[0].parsedRequest!.parts[0] as SerializableVariablePart;
expect(serializedVar.variableId).to.equal('f');
expect(serializedVar.variableArg).to.equal('main.ts');
expect(serializedVar.variableValue).to.equal('file content of main.ts');
expect(serializedVar.variableDescription).to.equal('File variable');
const restored = new MutableChatModel(serialized);
const restoredPart = restored.getRequests()[0].message.parts[0] as ParsedChatRequestVariablePart;
expect(restoredPart.variableArg).to.equal('main.ts');
expect(restoredPart.resolution?.variable.id).to.equal('f');
expect(restoredPart.resolution?.value).to.equal('file content of main.ts');
expect(restoredPart.resolution?.variable.description).to.equal('File variable');
});
});
});