Skip to content

Commit

Permalink
Basis correlation fix (#843)
Browse files Browse the repository at this point in the history
Fixed basis view on tagged interactions
  • Loading branch information
therealryan authored Jun 13, 2024
1 parent 6380532 commit bf42d13
Show file tree
Hide file tree
Showing 14 changed files with 314 additions and 36 deletions.
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

0 comments on commit bf42d13

Please sign in to comment.