dodona-edu / universal-judge Goto Github PK
View Code? Open in Web Editor NEWUniversal judge for educational software testing
Home Page: https://docs.dodona.be/en/tested
License: MIT License
Universal judge for educational software testing
Home Page: https://docs.dodona.be/en/tested
License: MIT License
In hoofdstuk drie worden voorbeelden gegeven van soorten oefeningen die ondersteund worden door de generieke judge. Daar is op dit moment sprake van drie soorten oefeningen die zullen besproken worden, maar misschien zijn er nog extra waarvan we een voorbeeld zouden willen geven:
bash
shell scripts in computergebruikecho 'SPAM' | ...
(moet bv. MAPS
uitschrijven op stdout; testgevallen bestaan telkens uit stuk commandolijn met lichte varianten, hier de string die uitgeschreven wordt op stdin
, waar de ingediende oplossing dan moet ingevuld worden op de plaats van de drie puntjes)Vergeet je ook niet ergens ruimte te voorzien om de real world test van je judge op Dodona te bespreken. Je hoeft dit nu nog niet per se uit te schrijven (we hebben een beoordeling op de GitHub issue), maar ergens een stub voorzien dat het niet vergeten wordt, kan geen kwaad.
In de nota's op de tekst staat een boomstructuur dat een goed begin is. Daarvan verder werken zou wel enkel voordelen opleveren:
Concreet zou het gaan om:
Dit zou het ook gemakkelijker maken om ooit uit te breiden naar een meer volledige AST, maar dat is momenteel niet de bedoeling van deze issue.
Het idee is om de gegevenstypes op te delen in twee categorieën:
integer
, rational
, text
, boolean
, sequence
, set
en map
.tuple
uit Python ondersteunen, zal het vanzelf omgezet worden naar een list
(maar bv. in Haskell kan het wel omgezet worden naar een tuple
). Er is ook de mogelijk dat implementaties voor programmeertalen expliciet een bepaald type niet ondersteunen. Zo zal de Java-implementatie geen uint64
(een unsigned 64-bit integer) ondersteunen, omdat er geen equivalent bestaat in de taal. Een voorbeeld:TESTed -> | int8 |
uint8 |
int16 |
uint16 |
int32 |
uint32 |
int64 |
uint64 |
---|---|---|---|---|---|---|---|---|
Python | int |
int |
int |
int |
int |
int |
int |
int |
Java | byte |
short |
short |
int |
int |
long |
long |
- |
C | int8_t |
uint8_t |
int16_t |
uint16_t |
int32_t |
uint32_t |
int64_t |
uint64_t |
Haskell | Integer |
Integer |
Integer |
Integer |
Integer |
Integer |
Integer |
Integer |
Het grote voordeel is dat er meer types kunnen, zoals bv. list
en tuple
in Python, maar ook array
en List
in Java.
In beide gevallen misschien een soort functie voorzien zodat niet elke evaluator dit moet implementeren.
accepted
en een tekstuele diff
.Sowieso in beide gevallen strikte controle in de judge voor we het doorsturen naar Dodona.
Momenteel heb ik de exitcode toegevoegd zoals andere "channels" (stdout, stderr, ...) aan een testcase. Dit is niet helemaal juist: er namelijk slechts één exitcode per context. Potentieel is er dus een probleem, waarbij verschillende testcases binnen één context andere exitcodes verwachten, wat dus nooit gaat werken.
Idee: move to main testcase:
Het enige dat verschilt is eigenlijk evaluator_executor
, dus zou dit gemakkelijk in dezelfde map kunnen.
Vervolg van #11. De vertaling naar Haskell is niet altijd triviaal. Verdergaan op het voorbeeld, stel dat de Tree
een functie right
heeft:
public class Tree<T> {
public Tree<T> right() {
return this.r;
}
}
In het testplan zou dit opgesteld worden als twee testcases:
Tree<?> tree = new Tree<>();
assert tree.right() == null;
In Haskell veronderstel ik dat hetzelfde implementeren iets zal worden als:
data Tree a = Parent (Tree a) (Tree a)
| Leaf
right :: Tree a -> Maybe (Tree a)
right (Parent l r) = Just r
right Leaf = Nothing
In dit geval zijn er ook twee testcases:
t = Parent Leaf Leaf
assert (right t) == Just Leaf
Vragen voor later of tijdens een vergadering:
Willen we dit soort vertaling doen in de judge? Hoever willen we daar in gaan? Welke paradigma willen we ondersteunen? (Misschien is het ook eens de moeite om naar enkele oefeningen te kijken die Haskell gebruiken, om te zien wat er juist nodig is)
Er zal wel een mogelijkheid bestaan om te weten welke bestanden aangemaakt zijn door een proces.
Dit zou kunnen gebruikt worden om de "file channel" te verbeteren met de mogelijkheid om het maken van bestanden als fout te rekenen.
De judge liefst met alle mogelijke manieren waarop het verkeerd kan gaan overweg kunnen. Doelen, in volgorde van belangrijkheid:
Waar is de judge op voorzien:
exit(150)
)Moeilijker:
Gemigreerd van https://github.com/niknetniko/test-judge/issues/2
Ik heb de parallelle uitvoering van de contexten verwijderd voor het implementeren van de time-out.
Concreet zou ik overal de vermelding van parallelle uitvoering verwijderden, met uitzondering van de paragraaf over performantie, waar ik bovenstaande uitleg kan doen.
Een stuk code dat uitgevoerd wordt als "functie-oproep". Eventueel, maar niet noodzakelijk, gekoppeld aan taalspecifieke evaluator (#3)
Te doen:
Bij de parallelle uitvoering zijn twee problemen die ik momenteel zie:
Dat laatste is een probleem als we ooit toch op Dodona willen overschakelen voor time-outs (stel dat er een modus komt om geplande testen eerst aan te geven, zoals Peter zei).
Een mogelijkheid is geen parallelle uitvoering meer doen; dat is wel jammer omdat de contexten zelf onafhankelijk zijn, maar anderzijds is de snelheidswinst beperkt of onduidelijk (op de workers van dodona in elk geval).
Research how we can use PEML as DSL to write exercises
Inspiratie op https://en.wikipedia.org/wiki/Shebang_(Unix), leuk voor de demo.
Syntaxis:
#!tested [programmeertaal]
Enkele ideeën:
Termen:
Gedaan deze week:
none
specificeert, d.w.z. er geen uitvoer op het exceptions-kanaal verwacht wordt, zal de uitvoer van het kanaal gebruikt worden als foutboodschap van de andere kanalenDit zou leuk zijn om ook te hebben in het generieke deel, maar:
Zie ook #10.
Er zijn drie soorten oefeningen:
Echter:
Uiteraard kunnen de drie modi vermeld worden, maar ik zou aan de hand van het tweede soort oefening uitleggen hoe alles werkt.
Zoals besproken tijdens de meeting:
Op dit moment heeft de functie-oproep volgende data:
type
: het soort functie-oproep, zie hierondername
: de naam van de functieobject
: (optioneel) waarop de functie opgeroepen wordtarguments
: lijst van waarden, in het serialisatieformaatEr zijn momenteel twee soorten functies:
top
: top-level functiesobject
: functies die op een object opgeroepen worden, bv. een klasse of instantieNiet elke taal ondersteunt top-level functies (bv. Java). Bij dergelijke talen worden top-leven functies omgezet naar object-functies, met als object het object waarin de ingediende code zich bevindt, om een zo goed mogelijke benadering te maken.
Een voorbeeld schept klaarheid:
Main.java
zit een klasse Main
, voor Python zit de code in submission.py
.max(5, 10)
.Dit testplan in Python zou gewoon een oproep genereren voor een functie max
in submission.py
. In het geval van Java zal een oproep gegenereerd worden voor een statische functie op de klasse van de ingediende code: Main.max
.
Zoals in de rest van de judge is er geen ondersteuning voor andere niveau's van indeling, zoals Java-packages of -modules, Haskell-modules, enz.
Te doen:
Misschien te doen:
In vroegere versies van de code bevatte het functie-oproep mechanisme een main
-type alsook een onderscheid tussen static
en niet-statische functies.
Het type main
is verwijderd omdat de toegevoegde complexiteit niet opwoog tegen de voordelen. Main-functies worden nu volledig apart behandeld in de sjablonen.
Het onderscheid tussen statische en niet-statische functies is verwijderd omdat het niet nuttig was; dit onderscheid kan nog steeds gebeuren door het attribuut object
juist in te stellen.
Uit de e-mail:
Een speciaal geval is van geprogrammeerde evaluatie, die je een "orakel" zou kunnen noemen.
Voorbeeld: oefening waarbij de leeftijd van een persoon moet berekend worden (op vandaag), gegeven de geboortedatum van die persoon. Daarbij kan dus de verwachte waarde niet statisch in het testplan zitten, maar het kan wel berekend worden door een orakel. Dit orakel kan nu al vervat zitten in de geprogrammeerde evaluatie, maar het zou eventueel ook kunnen:
- berekend worden in het testplan (dynamisch testplan), dus voorafgaand aan het genereren van de testcode
- berekend worden door het orakel en geëvalueerd worden door TESTed als het resultaat een ondersteund datatype heeft (zoals in dit geval een integer); met andere woorden, de geprogrammeerde evaluatie bestaat er dan enkel in om op basis van de input (geboortedatum) de verwachte output (leeftijd) te genereren en die terug te geven aan TESTed, die dan op zijn beurt de gelijkheid van de verwachte waarde (gegenereerd door het orakel) en de gegenereerde waarde (door de ingediende oplossing) kan controleren
In die zin werkt het "orakel" eerder op dezelfde manier als de uitvoeringsomgeving, dan als de evaluatieomgeving, want ze moet enkel resultaten afleveren (hetzij voor integratie in het testplan of voor gebruik in de evaluatiestap van TESTed). Voor wie het testplan opstelt, zou dat betekenen dat een (deel van een) voorbeeldoplossing moet aangeleverd worden (in een programmeertaal die door TESTed ondersteund wordt.
Momenteel is dat enkel tekst, maar het kan handig zijn om ook het formaat (en als we toch bezig zijn ook de zichtbaarheid) te kunnen opgeven: op dat moment kunnen we zelfs het formaat van Dodona gewoon gebruiken.
Zal op een zeer gelijkaardige manier werken als de taalspecifieke evaluatoren, behalve dat hier dezelfde code voor alle talen wordt gebruikt.
Bij de taalspecifieke evaluatoren wordt de waarde rechtstreeks aan de evaluatiefunctie gegeven, die uitgevoerd wordt in de context van de studentcode.
Hier zal de waarde geserialiseerd worden, en via de judge naar de evaluatiecode gestuurd worden. Deze laatste evaluatiecode voert niet uit in de context van de studentcode. De judge zal ook de waarde deserialiseren naar objecten in de taal van de evaluator.
An optional context or testcase that uses a construct not supported by the programming language of the submitted solution would be skipped, instead of flagging a no-language-support for the entire testplan.
Het valt te overwegen om exceptions als apart kanaal te voorzien, om bv. te controleren dat stuk code de juiste exception smijt.
Te bepalen:
IndexOutOfBounds
, ...) Of is dit taalspecifiek?Momenteel beperkt de controle op comptabiliteit met een programmeertaal tot dingen die TESTed nodig heeft (een testplan waarbij bv. set
s gebruikt worden zal niet werken in talen zonder set
).
Er is nog een ander aspect dat niet gecontroleerd wordt: is de oefening oplosbaar in de programmeertaal. Bij de ISBN-opgave bijvoorbeeld:
Schrijf een functie is_isbn waaraan een string c (str) moet doorgegeven worden. De functie moet een Booleaanse waarde (bool) teruggeven, die aangeeft of c een geldige ISBN-code is. De functie heeft ook nog een optionele tweede parameter isbn13 waaraan een Booleaanse waarde (bool) kan doorgegeven worden die aangeeft of het om een ISBN-10 code (False) of om een ISBN-13 code (True, standaardwaarde) moet gaan.
Deze opgave impliceert dat er een manier is om optionele parameters te hebben in de taal. In Java is dit opgevangen met overloading, maar dat is niet mogelijk in alle talen. In C zou er rond gewerkt kunnen worden met een macro (denk ik, nog niet gedaan), maar ik heb nog niet echt een goede oplossing gevonden voor Haskell.
Hier zijn meerdere pistes mogelijk:
function signatures
af uit de oproepen in het testplan, en controleren vervolgens of de taal dat ondersteunt (of we eisen dat deze signatures ook in het testplan zijn, maar dat gaat is minder eenvoudig)Een ander, gerelateerd aspect zijn dynamische types van argumenten. In Python geen probleem, Java ook nog doenbaar met overloading, maar Haskell en C worden weer moeilijk.
Zie #20.
When comparing file content line by line, trailing newlines are trimmed by default.
Another option would be not to trim these newlines automatically (.splitlines(True)
) and add an explicit option for trailing newline trimming (one? multiple?) to textual comparisons. This way, we leave full freedom in testing whether or not the last line of a text file should end with a newline. This is impossible if newlines are trimmed upfront.
Voor ik een PR maak op Dodona nog een vraag: momenteel (lokaal) zit dat zo in het formaat:
"close-test": {
"type": "object",
"description": "Close the current test. Accepted iff status is correct, but you can overwrite this.",
"required": ["command", "status", "generated"],
"properties": {
"command": { "enum": ["close-test"] },
"generated": { "type": "string" },
"accepted": { "type": "boolean" },
"status": { "$ref": "#/definitions/status" },
"data": { "type": "object" } // <---- HIER
}
}
De vraag is of het veldje data
"getypeerd" moet worden, of mag dat gewoon een object zijn zoals nu? Indien het een schema moet krijgen, wat mag er dan in zitten?
Ook iets als 80% van het totaal voor het subproces.
Soms wordt de secret als suffix gebruikt, soms als prefix.
Enkele pointers van prof. Dawyndt:
- some related terms
- interface description language (IDL)
Vereisten:
Te doen:
The reason I initially took the easy road here by adopting the Python single quote default for string literals, is that there's an extra step needed to escape double quotes inside a string literal enclosed in double quotes. I think this still needs to be done here, by replacing any double quote by an escaped double quote, unless it's already escaped.
Ik begin met de hoofdstuk 5 van de thesis te lezen, en wil graag een overzicht maken van "ontbrekende features die we halen uit analyse van bestaande judges" en "ontbrekende features om meertalige oefeningen te ondersteunen in Dodona". Voor mij ligt nu nog niet vast of dit uiteindelijk nog in hoofdstuk 5 moet komen, en ik vraag me op dit moment ook nog niet af of we de features wel willen en of we ze finaal ook moeten implementeren. Is in eerste plaats een boekhouding van ideeën die nog opkomen, en die eventueel kunnen meegenomen worden in een vervolgthesis of bij het verder afwerken van TESTed.
De tekst bevat nu nog geen bespreking van de stub die voorzien is om een linter te configureren voor de programmeertaal.
Hier zijn twee ideeën voor:
Gedaan
naam = functieoproep
constructor
-type en identity
-type
str()
(en repr
?) of len()
?Mee bezig
Zie #8 voor een lijst van ondersteunde datatypes. Om de implementatie eenvoudiger te houden, is het best om onmiddellijk voor alle types het type ook apart mee te geven, los van hoe we het in json implementeren (bv. ook bij strings al het type string
meegeven).
Ik zou de term "default arguments" hernoemen naar "default parameters". Dan is ook het verschil met "named arguments" duidelijker en wordt ook de meer gangbare terminologie gebruikt.
De term parameter wordt gebruikt voor een (abstracte) invoerkanaal waarop informatie aan een functie/methode kan doorgegeven. Dit wordt vastgelegd bij het definiëren van de functie/methode. Bij de definitie kan er ook een standaardwaarde gekoppeld worden aan het invoerkanaal, en daarom noemen we het een "default parameter".
Bij het aanroepen van een functie kan aan elk invoerkanaal een waarde doorgegeven worden. Die waarde noemen we een argument. De koppeling tussen de argumenten en de parameters kan positioneel of benoemd zijn. We spreken in dat laatste geval van named arguments (benoemde argumenten) of keyword arguments.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.