Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basis correlation fix #843

Merged
merged 2 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ void chunkLoadingPath() throws Exception {
assertEquals( "[\"res/\"+]", delta.getTarget().getLines().toString(),
"inserted lines count" );

int context = 15;
int context = 14;
String before = resource.substring(
delta.getSource().getPosition() - context,
delta.getSource().getPosition() + context )
Expand All @@ -258,9 +258,9 @@ void chunkLoadingPath() throws Exception {
+ delta.getTarget().getLines().get( 0 ).length() )
.replaceAll( "\\d", "#" );

assertEquals( "f),[])),a.u=e=>(###===e?\"commo",
assertEquals( "),[])),a.u=e=>(###===e?\"comm",
before, "raw resource runtime snippet" );
assertEquals( "f),[])),a.u=e=>\"res/\"+(###===e?\"commo",
assertEquals( "),[])),a.u=e=>\"res/\"+(###===e?\"comm",
after, "written runtime snippet" );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,14 @@ static void setup() throws Exception {
.prerequisite( problem )
.prerequisite( confirmation )
.context( GroupState.class, gs -> gs.che().guilt( "undeniable" ) )
.update( i -> i.responder() == CHE, i -> i.response()
.set( ".+", "No, I'm worried about her dairy consumption.\n"
.update( i -> i.responder() == CHE, i -> i
.tags( Tags.add( "denial" ) )
.response().set( ".+", "No, I'm worried about her dairy consumption.\n"
+ "I'm cutting you both off" ) )
.addCall( i -> i.responder() == BEN, 1, a -> a
.to( CHE ).tags( Tags.add( "confirmation" ) )
.request( new Text( "She's an adult, she can have cheese if she wants to!" ) )
.response( new Text( "Feel free to shop elsewhere." ) ) )
.update( i -> i.responder() == BEN, i -> i.response()
.set( ".+", "Sorry Ava, no brie today" ) )
.residue( GroupState.class, gs -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ void messages() {
.onTransmission( "BEN response" );

fseq.onExpected()
.hasUrlArgs( "display=Expected", "msg=3" )
.hasUrlArgs( "display=Expected", "msg=5" )
.hasMessage(
"Sorry Ava, no brie today" );

fseq.onActual()
.hasUrlArgs( "msg=3" ) // Actual is the default, no arg required
.hasUrlArgs( "msg=5" ) // Actual is the default, no arg required
.hasMessage(
"Sorry Ava, no brie today, or ever." );

fseq.onDiff()
.hasUrlArgs( "display=Diff", "msg=3" )
.hasUrlArgs( "display=Diff", "msg=5" )
.hasMessage(
"1 - Sorry Ava, no brie today",
"1 + Sorry Ava, no brie today, or ever." );
Expand All @@ -61,7 +61,7 @@ void search() {
fseq.toggleSearch()
.search( "brie" )
.hasUrlArgs(
"msg=3",
"msg=5",
"search=brie" )
.hasSearchHits(
"BEN request : expected",
Expand All @@ -74,7 +74,7 @@ void search() {
fseq.toggleSearch()
.search( "or" )
.hasUrlArgs(
"msg=3",
"msg=5",
"search=or" )
.hasSearchHits(
"CHE response : expected actual",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ void logFilters() {
LogSequence lseq = dseq.logs();

lseq.levels( "WARN", "INFO" )
.hasUrlArgs( "lv=WARN%2CINFO", "msg=3", "tab=3" )
.hasUrlArgs( "lv=WARN%2CINFO", "msg=5", "tab=3" )
.hasMessages(
"0s Δ 0ms WARN abc message 1",
"0.05s Δ 50ms INFO def message 2",
Expand All @@ -49,13 +49,13 @@ void logFilters() {
"2.359s Δ 659ms WARN abc message 6" );

lseq.source( "def" )
.hasUrlArgs( "lv=WARN%2CINFO", "msg=3", "sf=def", "tab=3" )
.hasUrlArgs( "lv=WARN%2CINFO", "msg=5", "sf=def", "tab=3" )
.hasMessages(
"0.05s Δ 0ms INFO def message 2",
"1.7s Δ 1650ms INFO def message 5" );

lseq.message( "5" )
.hasUrlArgs( "lv=WARN%2CINFO", "mf=5", "msg=3", "sf=def", "tab=3" )
.hasUrlArgs( "lv=WARN%2CINFO", "mf=5", "msg=5", "sf=def", "tab=3" )
.hasMessages( "1.7s Δ 0ms INFO def message 5" );

// we can deep-link direct to filtered views
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protected AbstractResidueTest( String url ) {
@Test
void residue() {
dseq.residue()
.hasUrlArgs( "msg=3", "tab=2" )
.hasUrlArgs( "msg=5", "tab=2" )
.hasPanels( "Psychological state" )
.hasContent( "Psychological state",
"Model",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ void sequenceDiagram() {
" BEN request [e ]",
" CHE request [e ]",
" CHE response [e ap ] 100%",
" CHE request [e ]",
" CHE response [e ]",
" BEN response [e a f] 100%" );
}

Expand All @@ -39,7 +41,7 @@ void basis() {
FlowSequence fseq = dseq.flow().onTransmission( "BEN response" );

fseq.onBasis()
.hasUrlArgs( "display=Basis", "msg=3" )
.hasUrlArgs( "display=Basis", "msg=5" )
.hasMessage(
"1 + Sorry Ava, no brie today" );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ void sequenceDiagram() {
" BEN request [eb ]",
" CHE request [eb ]",
" CHE response [ebap ] 100%",
" CHE request [eb ]",
" CHE response [eb ]",
" BEN response [eba f] 100%" );
}

Expand All @@ -39,7 +41,7 @@ void basis() {
FlowSequence fseq = dseq.flow().onTransmission( "BEN response" );

fseq.onBasis()
.hasUrlArgs( "display=Basis", "msg=3" )
.hasUrlArgs( "display=Basis", "msg=5" )
.hasMessage(
"1 - Hi Ava! Here is your brie",
"1 + Sorry Ava, no brie today" );
Expand Down
3 changes: 2 additions & 1 deletion report/report-ng/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test --browsers ChromeHeadless --watch=false"
"test": "ng test --browsers ChromeHeadless --watch=false",
"testing": "ng test"
},
"private": true,
"dependencies": {
Expand Down
212 changes: 212 additions & 0 deletions report/report-ng/projects/report/src/app/basis-fetch.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import { TestBed } from '@angular/core/testing';

import { BasisFetchService, setDistance } from './basis-fetch.service';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Flow, Interaction, empty_flow, empty_interaction, empty_transmission } from './types';
import { defer, of } from 'rxjs';
import { Action, empty_action } from './seq-action/seq-action.component';

describe('BasisFetchService', () => {
let httpClientSpy: jasmine.SpyObj<HttpClient>;
let service: BasisFetchService;

beforeEach(() => {
TestBed.configureTestingModule({});
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
service = new BasisFetchService(httpClientSpy);
});

it('should be created', () => {
expect(service).toBeTruthy();
});

it('should request a flow', () => {
httpClientSpy.get.and.returnValue(detailPage(empty_flow));

service.get("detail_hash");

expect(httpClientSpy.get.calls.count())
.withContext('one call')
.toBe(1);
expect(httpClientSpy.get.calls.mostRecent().args[0])
.withContext("request path")
.toBe("detail_hash.html");
});

it('should cope with bad data', () => {
httpClientSpy.get.and.returnValue(of("not a detail page"));
service.get("detail_hash");

expect(service.message(action("", "", "")))
.withContext("nothing there")
.toBe(null);
});

it('should cope with malformed json', () => {
httpClientSpy.get.and.returnValue(of("// START_JSON_DATA\n{]\n// END_JSON_DATA"));
service.get("detail_hash");

expect(service.message(action("", "", "")))
.withContext("nothing there")
.toBe(null);
});

it('should cope with missing data', () => {
httpClientSpy.get.and.returnValue(of("// START_JSON_DATA\n{}\n// END_JSON_DATA"));
service.get("detail_hash");

expect(service.message(action("", "", "")))
.withContext("nothing there")
.toBe(null);
});

it('should match simple interactions', () => {
let flow = flowWithRoot(interaction("AVA", "BEN"));
httpClientSpy.get.and.returnValue(detailPage(flow));

service.get("detail_hash");

expect(service.message(action("AVA", "BEN", "BEN request")))
.withContext("matched request")
.toBe("request from AVA to BEN with tags []");

expect(service.message(action("BEN", "AVA", "BEN response")))
.withContext("matched response")
.toBe("response from BEN to AVA with tags []");

expect(service.message(action("AVA", "BEN", "BEN foobar")))
.withContext("bad label")
.toBe(null);

expect(service.message(action("AVA", "CHE", "CHE request")))
.withContext("actor mismatch")
.toBe(null);
});

it('should cope with tagging', () => {
let flow = flowWithRoot(interaction("AVA", "BEN", "abc"));
httpClientSpy.get.and.returnValue(detailPage(flow));

service.get("detail_hash");

expect(service.message(action("AVA", "BEN", "BEN request", "abc")))
.withContext("tag match")
.toBe("request from AVA to BEN with tags [abc]");

expect(service.message(action("AVA", "BEN", "BEN request")))
.withContext("no tags on query")
.toBe("request from AVA to BEN with tags [abc]");

expect(service.message(action("AVA", "BEN", "BEN request", "def")))
.withContext("mismatched tags on query")
.toBe("request from AVA to BEN with tags [abc]");
});

it('should find the best match', () => {
let flow = flowWithRoot(interaction("AVA", "BEN"));
flow.root.children = [
interaction("BEN", "CHE", "abc"),
interaction("BEN", "CHE", "abc", "def"),
interaction("BEN", "CHE", "def"),
];
httpClientSpy.get.and.returnValue(detailPage(flow));

service.get("detail_hash");

expect(service.message(action("BEN", "CHE", "CHE request", "abc")))
.withContext("first")
.toBe("request from BEN to CHE with tags [abc]");

expect(service.message(action("BEN", "CHE", "CHE request", "def")))
.withContext("third")
.toBe("request from BEN to CHE with tags [def]");

expect(service.message(action("BEN", "CHE", "CHE request", "abc", "def")))
.withContext("second")
.toBe("request from BEN to CHE with tags [abc,def]");
});

it('should compute set distance correctly', () => {
expect(service).toBeTruthy();
expect(setDistance([], []))
.withContext("empty")
.toBe(0);

expect(setDistance(["a"], []))
.withContext("single removed")
.toBe(1);
expect(setDistance([], ["a"]))
.withContext("single added")
.toBe(1);

expect(setDistance(["a", "b", "c"], []))
.withContext("multi removed")
.toBe(1);
expect(setDistance([], ["a", "b", "c"]))
.withContext("multi added")
.toBe(1);

expect(setDistance(["a"], ["a"]))
.withContext("single match")
.toBe(0);
expect(setDistance(["a"], ["b"]))
.withContext("single mismatch")
.toBe(1);

expect(setDistance(["a", "b", "c"], ["a", "b", "c"]))
.withContext("full match")
.toBe(0);
expect(setDistance(["a", "b", "c"], ["a", "b", "c", "d"]))
.withContext("better match")
.toBe(0.25);
expect(setDistance(["a"], ["a", "b", "c", "d"]))
.withContext("slight match")
.toBe(0.75);
expect(setDistance(["a", "w", "x"], ["a", "y", "z"]))
.withContext("worse match")
.toBe(0.8);
expect(setDistance(["a", "b", "c"], ["d", "e", "f"]))
.withContext("disjoint")
.toBe(1);
});

});

function detailPage(flow: Flow) {
let lines = [
"blah blah blah",
"// START_JSON_DATA",
];
JSON.stringify(flow, null, 2).split("\n").forEach(l => lines.push(l));
lines.push(
"// END_JSON_DATA",
"blah blah blah",
);
let page = lines.map((l) => l + "\n").join("");
return of(page);
}

function flowWithRoot(interaction: Interaction): Flow {
let flow: Flow = JSON.parse(JSON.stringify(empty_flow));
flow.root = interaction;
return flow;
}

function interaction(from: string, to: string, ...tags: string[]) {
let interaction = JSON.parse(JSON.stringify(empty_interaction));
interaction.requester = from;
interaction.request.full.expect = `request from ${from} to ${to} with tags [${tags}]`;
interaction.responder = to;
interaction.response.full.expect = `response from ${to} to ${from} with tags [${tags}]`;
interaction.tags = tags;
return interaction;
}

function action(from: string, to: string, label: string, ...tags: string[]): Action {
let action: Action = JSON.parse(JSON.stringify(empty_action));
action.fromName = from;
action.toName = to;
action.label = label;
action.tags = tags;
return action;
}
Loading