blob: c5d900a23a06da442797749a46cc9b862c4a964c [file] [log] [blame]
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="shortcut icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.1.2, mkdocs-material-5.5.3">
<title>Unit testing (EUnit) - Epsilon</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.947af8d5.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.7f672a1f.min.css">
<meta name="theme-color" content="">
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700%7CRoboto+Mono&display=fallback">
<style>body,input{font-family:"Roboto",-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono",SFMono-Regular,Consolas,Menlo,monospace}</style>
<link rel="stylesheet" href="../../assets/stylesheets/extra.css">
<link rel="stylesheet" href="../../assets/stylesheets/mermaid.css">
<link rel="stylesheet" href="../../assets/javascript/google-code-prettify/prettify.css">
<link rel="stylesheet" href="https://unpkg.com/mermaid@8.5.1/dist/mermaid.css">
<!-- FAVICON -->
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon-16x16.png">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="/assets/images/favicon.ico">
</head>
<body dir="ltr" data-md-color-scheme="" data-md-color-primary="black" data-md-color-accent="orange">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#the-epsilon-unit-testing-framework-eunit" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid" aria-label="Header">
<a href="../.." title="Epsilon" class="md-header-nav__button md-logo" aria-label="Epsilon">
<img src="../../assets/images/epsilon-white-background.png" alt="logo">
</a>
<label class="md-header-nav__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/></svg>
</label>
<div class="md-header-nav__title" data-md-component="header-title">
<div class="md-header-nav__ellipsis">
<span class="md-header-nav__topic md-ellipsis">
Epsilon
</span>
<span class="md-header-nav__topic md-ellipsis">
Unit testing (EUnit)
</span>
</div>
</div>
<label class="md-header-nav__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0116 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 019.5 16 6.5 6.5 0 013 9.5 6.5 6.5 0 019.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" data-md-state="active">
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0116 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 019.5 16 6.5 6.5 0 013 9.5 6.5 6.5 0 019.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</label>
<button type="reset" class="md-search__icon md-icon" aria-label="Clear" data-md-component="search-reset" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header-nav__source">
<a href="https://git.eclipse.org/c/epsilon/org.eclipse.epsilon.git/" title="Go to repository" class="md-source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05L244 40.45a28.87 28.87 0 00-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 01-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 000 40.81l195.61 195.6a28.86 28.86 0 0040.8 0l194.69-194.69a28.86 28.86 0 000-40.81z"/></svg>
</div>
<div class="md-source__repository">
Git repository @ Eclipse
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="Epsilon" class="md-nav__button md-logo" aria-label="Epsilon">
<img src="../../assets/images/epsilon-white-background.png" alt="logo">
</a>
Epsilon
</label>
<div class="md-nav__source">
<a href="https://git.eclipse.org/c/epsilon/org.eclipse.epsilon.git/" title="Go to repository" class="md-source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05L244 40.45a28.87 28.87 0 00-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 01-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 000 40.81l195.61 195.6a28.86 28.86 0 0040.8 0l194.69-194.69a28.86 28.86 0 000-40.81z"/></svg>
</div>
<div class="md-source__repository">
Git repository @ Eclipse
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." title="Home" class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item">
<a href="../../download/" title="Download" class="md-nav__link">
Download
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-3" type="checkbox" id="nav-3" checked>
<label class="md-nav__link" for="nav-3">
Documentation
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>
</span>
</label>
<nav class="md-nav" aria-label="Documentation" data-md-level="1">
<label class="md-nav__title" for="nav-3">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../" title="Overview" class="md-nav__link">
Overview
</a>
</li>
<li class="md-nav__item">
<a href="../emc/" title="Model connectivity" class="md-nav__link">
Model connectivity
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-3-3" type="checkbox" id="nav-3-3" checked>
<label class="md-nav__link" for="nav-3-3">
Languages
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>
</span>
</label>
<nav class="md-nav" aria-label="Languages" data-md-level="2">
<label class="md-nav__title" for="nav-3-3">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Languages
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../eol/" title="Object language (EOL)" class="md-nav__link">
Object language (EOL)
</a>
</li>
<li class="md-nav__item">
<a href="../egl/" title="Code generation (EGL)" class="md-nav__link">
Code generation (EGL)
</a>
</li>
<li class="md-nav__item">
<a href="../evl/" title="Model validation (EVL)" class="md-nav__link">
Model validation (EVL)
</a>
</li>
<li class="md-nav__item">
<a href="../etl/" title="Model transformation (ETL)" class="md-nav__link">
Model transformation (ETL)
</a>
</li>
<li class="md-nav__item">
<a href="../ecl/" title="Model comparison (ECL)" class="md-nav__link">
Model comparison (ECL)
</a>
</li>
<li class="md-nav__item">
<a href="../eml/" title="Model merging (EML)" class="md-nav__link">
Model merging (EML)
</a>
</li>
<li class="md-nav__item">
<a href="../epl/" title="Pattern matching (EPL)" class="md-nav__link">
Pattern matching (EPL)
</a>
</li>
<li class="md-nav__item">
<a href="../flock/" title="Model Migration (Flock)" class="md-nav__link">
Model Migration (Flock)
</a>
</li>
<li class="md-nav__item">
<a href="../emg/" title="Model generation (EMG)" class="md-nav__link">
Model generation (EMG)
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Unit testing (EUnit)
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 9h14V7H3v2m0 4h14v-2H3v2m0 4h14v-2H3v2m16 0h2v-2h-2v2m0-10v2h2V7h-2m0 6h2v-2h-2v2z"/></svg>
</span>
</label>
<a href="./" title="Unit testing (EUnit)" class="md-nav__link md-nav__link--active">
Unit testing (EUnit)
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Table of contents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#common-issues" class="md-nav__link">
Common Issues
</a>
</li>
<li class="md-nav__item">
<a href="#testing-with-junit" class="md-nav__link">
Testing with JUnit
</a>
</li>
<li class="md-nav__item">
<a href="#selected-approach" class="md-nav__link">
Selected Approach
</a>
</li>
<li class="md-nav__item">
<a href="#test-organization" class="md-nav__link">
Test Organization
</a>
<nav class="md-nav" aria-label="Test Organization">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#test-suites" class="md-nav__link">
Test Suites
</a>
</li>
<li class="md-nav__item">
<a href="#test-cases" class="md-nav__link">
Test Cases
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#test-specification" class="md-nav__link">
Test Specification
</a>
<nav class="md-nav" aria-label="Test Specification">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#ant-buildfile" class="md-nav__link">
Ant Buildfile
</a>
<nav class="md-nav" aria-label="Ant Buildfile">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#eunit-invocations" class="md-nav__link">
EUnit Invocations
</a>
</li>
<li class="md-nav__item">
<a href="#helper-targets" class="md-nav__link">
Helper Targets
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#eol-script" class="md-nav__link">
EOL script
</a>
<nav class="md-nav" aria-label="EOL script">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#data-bindings" class="md-nav__link">
Data bindings
</a>
</li>
<li class="md-nav__item">
<a href="#model-bindings" class="md-nav__link">
Model bindings
</a>
</li>
<li class="md-nav__item">
<a href="#additional-variables-and-built-in-operations" class="md-nav__link">
Additional variables and built-in operations
</a>
</li>
<li class="md-nav__item">
<a href="#assertions" class="md-nav__link">
Assertions
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#examples" class="md-nav__link">
Examples
</a>
<nav class="md-nav" aria-label="Examples">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#models-and-tasks-in-the-buildfile" class="md-nav__link">
Models and Tasks in the Buildfile
</a>
</li>
<li class="md-nav__item">
<a href="#models-and-tasks-in-the-eol-script" class="md-nav__link">
Models and Tasks in the EOL Script
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#extending-eunit" class="md-nav__link">
Extending EUnit
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../pinset/" title="Dataset extraction (Pinset)" class="md-nav__link">
Dataset extraction (Pinset)
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-3-4" type="checkbox" id="nav-3-4">
<label class="md-nav__link" for="nav-3-4">
Tools
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>
</span>
</label>
<nav class="md-nav" aria-label="Tools" data-md-level="2">
<label class="md-nav__title" for="nav-3-4">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Tools
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../picto/" title="Picto" class="md-nav__link">
Picto
</a>
</li>
<li class="md-nav__item">
<a href="../flexmi/" title="Flexmi" class="md-nav__link">
Flexmi
</a>
</li>
<li class="md-nav__item">
<a href="../eugenia/" title="Eugenia" class="md-nav__link">
Eugenia
</a>
</li>
<li class="md-nav__item">
<a href="../exeed/" title="Exeed" class="md-nav__link">
Exeed
</a>
</li>
<li class="md-nav__item">
<a href="../modelink/" title="Modelink" class="md-nav__link">
Modelink
</a>
</li>
<li class="md-nav__item">
<a href="../hutn/" title="HUTN" class="md-nav__link">
HUTN
</a>
</li>
<li class="md-nav__item">
<a href="../workflow/" title="Workflow (Ant tasks)" class="md-nav__link">
Workflow (Ant tasks)
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../articles/" title="Articles" class="md-nav__link">
Articles
</a>
</li>
<li class="md-nav__item">
<a href="../../examples/" title="Examples" class="md-nav__link">
Examples
</a>
</li>
<li class="md-nav__item">
<a href="https://www.youtube.com/epsilondevs" title="Screencasts" class="md-nav__link">
Screencasts
</a>
</li>
<li class="md-nav__item">
<a href="https://www.youtube.com/playlist?list=PLRwHao6Ue0YUecg7vEUQTrtySIWwrd_mI" title="Lectures" class="md-nav__link">
Lectures
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-3-9" type="checkbox" id="nav-3-9">
<label class="md-nav__link" for="nav-3-9">
Javadoc
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>
</span>
</label>
<nav class="md-nav" aria-label="Javadoc" data-md-level="2">
<label class="md-nav__title" for="nav-3-9">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Javadoc
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="https://download.eclipse.org/epsilon/2.0/javadoc/" title="Stable" class="md-nav__link">
Stable
</a>
</li>
<li class="md-nav__item">
<a href="https://download.eclipse.org/epsilon/interim/javadoc/" title="Interim" class="md-nav__link">
Interim
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-4" type="checkbox" id="nav-4">
<label class="md-nav__link" for="nav-4">
Issues
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>
</span>
</label>
<nav class="md-nav" aria-label="Issues" data-md-level="1">
<label class="md-nav__title" for="nav-4">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Issues
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/enter_bug.cgi?product=epsilon" title="Report a new issue" class="md-nav__link">
Report a new issue
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?product=epsilon&cmdtype=doit&order=Reuse+same+sort+as+last+time&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=blocker&bug_severity=critical&bug_severity=major&bug_severity=normal&bug_severity=minor&bug_severity=trivial" title="View open bugs" class="md-nav__link">
View open bugs
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?product=epsilon&cmdtype=doit&order=Reuse+same+sort+as+last+time&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=enhancement" title="View enhancement requests" class="md-nav__link">
View enhancement requests
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?bug_status=RESOLVED&list_id=17694438&product=epsilon&query_format=advanced" title="View issues resolved since the last stable release" class="md-nav__link">
View issues resolved since the last stable release
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?product=epsilon&cmdtype=doit&order=Reuse+same+sort+as+last+time" title="View all issues" class="md-nav__link">
View all issues
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-5" type="checkbox" id="nav-5">
<label class="md-nav__link" for="nav-5">
Community
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>
</span>
</label>
<nav class="md-nav" aria-label="Community" data-md-level="1">
<label class="md-nav__title" for="nav-5">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Community
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-5-1" type="checkbox" id="nav-5-1">
<label class="md-nav__link" for="nav-5-1">
Who is using Epsilon?
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>
</span>
</label>
<nav class="md-nav" aria-label="Who is using Epsilon?" data-md-level="2">
<label class="md-nav__title" for="nav-5-1">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Who is using Epsilon?
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../users/" title="Industry" class="md-nav__link">
Industry
</a>
</li>
<li class="md-nav__item">
<a href="../../users/education/" title="Education" class="md-nav__link">
Education
</a>
</li>
<li class="md-nav__item">
<a href="../../users/open-source/" title="Open-source projects" class="md-nav__link">
Open-source projects
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="https://projects.eclipse.org/projects/modeling.epsilon/who" title="Who is developing Epsilon?" class="md-nav__link">
Who is developing Epsilon?
</a>
</li>
<li class="md-nav__item">
<a href="https://www.eclipse.org/forums/index.php/f/22/" title="Forum" class="md-nav__link">
Forum
</a>
</li>
<li class="md-nav__item">
<a href="../../labs/" title="Epsilon Labs" class="md-nav__link">
Epsilon Labs
</a>
</li>
<li class="md-nav__item">
<a href="../../faq/" title="Frequently asked questions" class="md-nav__link">
Frequently asked questions
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../branding/" title="Branding" class="md-nav__link">
Branding
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</span>
Table of contents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#common-issues" class="md-nav__link">
Common Issues
</a>
</li>
<li class="md-nav__item">
<a href="#testing-with-junit" class="md-nav__link">
Testing with JUnit
</a>
</li>
<li class="md-nav__item">
<a href="#selected-approach" class="md-nav__link">
Selected Approach
</a>
</li>
<li class="md-nav__item">
<a href="#test-organization" class="md-nav__link">
Test Organization
</a>
<nav class="md-nav" aria-label="Test Organization">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#test-suites" class="md-nav__link">
Test Suites
</a>
</li>
<li class="md-nav__item">
<a href="#test-cases" class="md-nav__link">
Test Cases
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#test-specification" class="md-nav__link">
Test Specification
</a>
<nav class="md-nav" aria-label="Test Specification">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#ant-buildfile" class="md-nav__link">
Ant Buildfile
</a>
<nav class="md-nav" aria-label="Ant Buildfile">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#eunit-invocations" class="md-nav__link">
EUnit Invocations
</a>
</li>
<li class="md-nav__item">
<a href="#helper-targets" class="md-nav__link">
Helper Targets
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#eol-script" class="md-nav__link">
EOL script
</a>
<nav class="md-nav" aria-label="EOL script">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#data-bindings" class="md-nav__link">
Data bindings
</a>
</li>
<li class="md-nav__item">
<a href="#model-bindings" class="md-nav__link">
Model bindings
</a>
</li>
<li class="md-nav__item">
<a href="#additional-variables-and-built-in-operations" class="md-nav__link">
Additional variables and built-in operations
</a>
</li>
<li class="md-nav__item">
<a href="#assertions" class="md-nav__link">
Assertions
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#examples" class="md-nav__link">
Examples
</a>
<nav class="md-nav" aria-label="Examples">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#models-and-tasks-in-the-buildfile" class="md-nav__link">
Models and Tasks in the Buildfile
</a>
</li>
<li class="md-nav__item">
<a href="#models-and-tasks-in-the-eol-script" class="md-nav__link">
Models and Tasks in the EOL Script
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#extending-eunit" class="md-nav__link">
Extending EUnit
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="the-epsilon-unit-testing-framework-eunit">The Epsilon Unit Testing Framework (EUnit)<a class="headerlink" href="#the-epsilon-unit-testing-framework-eunit" title="Permanent link">&para;</a></h1>
<p>EUnit is an unit testing framework specifically designed to test model management tasks, based on EOL and the Ant workflow tasks. It provides assertions for comparing models, files and directories. Tests can be reused with different sets of models and input data, and differences between the expected and actual models can be graphically visualized. This chapter describes how tests are organized and written and shows two examples of how a model-to-model transformation can be tested with EUnit. This chapter ends with a discussion of how EUnit can be extended to support other modelling and model management technologies.</p>
<h3 id="common-issues">Common Issues<a class="headerlink" href="#common-issues" title="Permanent link">&para;</a></h3>
<p>While each type of model management task does have specific complexity, below is a list of common concerns:</p>
<ul>
<li>
<p>There is usually a large number of models to be handled. Some may be created by hand, some may be generated using hand-written programs, and some may be generated automatically following certain coverage criteria.</p>
</li>
<li>
<p>A single model or set of models may be used in several tasks. For instance, a model may be validated before performing an in-place transformation to assist the user, and later on it may be transformed to another model or merged with a different model. This requires having at least one test for each valid combination of models and sets of tasks.</p>
</li>
<li>
<p>Test oracles are more complex than in traditional unit testing: instead of checking scalar values or simple lists, entire graphs of model objects or file trees may have to be compared. In some cases, complex properties in the generated artifacts may have to be checked.</p>
</li>
<li>
<p>Models and model management tasks may use a wide range of technologies. Models may be based on Ecore, XML files or Java object graphs, among many others. At the same time, tasks may use technologies from different platforms, such as Epsilon, or AMMA. Many of these technologies offer high-level tools for running and debugging the different tasks using several models. However, users wishing to do automated unit testing need to learn low-level implementation details about their modelling and model management technologies. This increases the initial cost of testing these tasks and hampers the adoption of new technologies.</p>
</li>
<li>
<p>Existing testing tools tend to focus on the testing technique itself, and lack integration with external systems. Some tools provide graphical user interfaces, but most do not generate reports which can be consumed by a continuous integration server, for instance.</p>
</li>
</ul>
<h3 id="testing-with-junit">Testing with JUnit<a class="headerlink" href="#testing-with-junit" title="Permanent link">&para;</a></h3>
<p>The previous issues are easier to understand with a concrete example. This section shows how a simple transformation between two EMF models in ETL using JUnit 4 would be normally tested, and points out several issues due to JUnit's limitations as a general-purpose unit testing framework for Java programs.</p>
<p>For the sake of brevity, only an outline of the JUnit test suite is included. All JUnit test suites are defined as Java classes. This test suite has three methods:</p>
<ol>
<li>
<p>The test setup method (marked with the <code>@Before</code> JUnit annotation) loads the required models by creating and configuring instances of . After that, it prepares the transformation by creating and configuring an instance of , adding the input and output models to its model repository.</p>
</li>
<li>
<p>The test case itself (marked with <code>@Test</code>) runs the ETL transformation and uses the generic comparison algorithm implemented by EMF Compare to perform the model comparison.</p>
</li>
<li>
<p>The test teardown method (marked with <code>@After</code>) disposes of the models.</p>
</li>
</ol>
<p>Several issues can be identified in each part of the test suite. First, test setup is tightly bound to the technologies used: it depends on the API of the and classes, which are both part of Epsilon. Later refactorings in these classes may break existing tests.</p>
<p>The test case can only be used for a single combination of input and output models. Testing several combinations requires either repeating the same code and therefore making the suite less maintainable, or using parametric testing, which may be wasteful if not all tests need the same combinations of models.</p>
<p>Model comparison requires the user to manually select a model comparison engine and integrate it with the test. For comparing EMF models, EMF Compare is easy to use and readily available. However, generic model comparison engines may not be available for some modelling technologies, or may be harder to integrate.</p>
<p>Finally, instead of comparing the obtained and expected models, several properties could have been checked in the obtained model. However, querying models through Java code can be quite verbose.</p>
<h3 id="selected-approach">Selected Approach<a class="headerlink" href="#selected-approach" title="Permanent link">&para;</a></h3>
<p>Several approaches could be followed to address these issues. Our first instinct would be to extend JUnit and reuse all the tooling available for it. A custom test runner would simplify setup and teardown, and modelling platforms would integrate their technologies into it. Since Java is very verbose when querying models, the custom runner should run tests in a higher-level language, such as EOL. However, JUnit is very tightly coupled to Java, and this would impose limits on the level of integration we could obtain. For instance, errors in the model management tasks or the EOL tests could not be reported from their original source, but rather from the Java code which invoked them. Another problem with this approach is that new integration code would need to be written for each of the existing platforms.</p>
<p>Alternatively, we could add a new language exclusively dedicated to testing to the Epsilon family. Being based on EOL, model querying would be very concise, and with a test runner written from scratch, test execution would be very flexible. However, this would still require all platforms to write new code to integrate with it, and this code would be tightly coupled to Epsilon.</p>
<p>As a middle ground, we could decorate EOL to guide its execution through a new test runner, while reusing the Apache Ant tasks already provided by several of the existing platforms, such as AMMA or Epsilon. Like Make, Ant is a tool focused on automating the execution of processes such as program builds. Unlike Make, Ant defines processes using XML <em>buildfiles</em> with sets of interrelated <em>targets</em>. Each target contains in turn a sequence of <em>tasks</em>. Many Ant tasks and Ant-based tools already exist, and it is easy to create a new Ant task.</p>
<p>Among these three approaches, EUnit follows the last one. Ant tasks take care of model setup and management, and tests are written in EOL and executed by a new test runner, written from the ground up.</p>
<h2 id="test-organization">Test Organization<a class="headerlink" href="#test-organization" title="Permanent link">&para;</a></h2>
<p>EUnit has a rich data model: test suites are organized as trees of tests, and each test is divided into many parts which can be extended by the user. This section is dedicated to describing how test suites and tests are organized. The next section indicates how they are written.</p>
<h3 id="test-suites">Test Suites<a class="headerlink" href="#test-suites" title="Permanent link">&para;</a></h3>
<p>EUnit test suites are organized as trees: inner nodes group related test cases and define <em>data</em> bindings. Leaf nodes define <em>model</em> bindings and run the test cases.</p>
<p>Data bindings repeat all test cases with different values in one or more variables. They can implement parametric testing, as in JUnit 4. EUnit can nest several data bindings, running all test cases once for each combination.</p>
<p>Model bindings are specific to EUnit: they allow developers to repeat a single test case with different subsets of models. Data and model bindings can be combined. One interesting approach is to set the names of the models to be used in the model binding from the data binding, as a quick way to try several test cases with the same subsets of models.</p>
<p>The figure below shows an example of an EUnit test tree: nodes with data bindings are marked with <code>data</code>, and nodes with model bindings are marked with <code>model</code>.</p>
<div class="mermaid mermaid-90">graph TD
data1[data&lt;br/&gt;x=1]
data2[data&lt;br/&gt;x=2]
testa1[test A]
testb1[test B]
testa2[test A]
testb2[test B]
modelx1[model X]
modely1[model Y]
modelx2[model X]
modely2[model Y]
root --&gt; data1
root --&gt; data2
data1 --&gt; testa1
data1 --&gt; testb1
data2 --&gt; testa2
data2 --&gt; testb2
testa1 --&gt; modelx1
testa1 --&gt; modely1
testa2 --&gt; modelx2
testa2 --&gt; modely2</div>
<p>EUnit will perform a preorder traversal of this tree, running the following tests:</p>
<ol>
<li>
<p><code>A</code> with <code>x = 1</code> and model X.</p>
</li>
<li>
<p><code>A</code> with <code>x = 1</code> and model Y.</p>
</li>
<li>
<p><code>B</code> with <code>x = 1</code> and both models.</p>
</li>
<li>
<p><code>A</code> with <code>x = 2</code> and model X.</p>
</li>
<li>
<p><code>A</code> with <code>x = 2</code> and model Y.</p>
</li>
<li>
<p><code>B</code> with <code>x = 2</code> and both models.</p>
</li>
</ol>
<p>Optionally, EUnit can filter tests by name, running only <code>A</code> or <code>B</code>. Similarly to JUnit, EUnit logs start and finish times for each node in the tree, so the most expensive test cases can be quickly detected. However, EUnit logs CPU time<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup> in addition to the usual wallclock time.</p>
<p>Parametric testing is not to be confused with <em>theories</em>: both repeat a test case with different values, but results are reported quite differently. While parametric testing produces separate test cases with independent results, theories produce aggregated tests which only pass if the original test case passes for every data point. The figures below illustrate these differences. EUnit does not support theories yet: however, they can be approximated with data bindings.</p>
<p><div class="mermaid mermaid-50">graph TD
data1[data 1]
data2[data 2]
testa1[test 1]
testb1[test 2]
testa2[test 1]
testb2[test 2]
root --&gt; data1
root --&gt; data2
data1 --&gt; testa1
data1 --&gt; testb1
data2 --&gt; testa2
data2 --&gt; testb2</div>
Parametric Testing</p>
<p><div class="mermaid mermaid-50">graph TD
data1[test 1]
data2[test 2]
testa1[data 1]
testb1[data 2]
testa2[data 1]
testb2[data 2]
root --&gt; data1
root --&gt; data2
data1 --&gt; testa1
data1 --&gt; testb1
data2 --&gt; testa2
data2 --&gt; testb2</div>
Theories</p>
<h3 id="test-cases">Test Cases<a class="headerlink" href="#test-cases" title="Permanent link">&para;</a></h3>
<p>The execution of a test case is divided into the following steps:</p>
<ol>
<li>
<p>Apply the data bindings of its ancestors.</p>
</li>
<li>
<p>Run the model setup sections defined by the user.</p>
</li>
<li>
<p>Apply the model bindings of this node.</p>
</li>
<li>
<p>Run the regular setup sections defined by the user.</p>
</li>
<li>
<p>Run the test case itself.</p>
</li>
<li>
<p>Run the teardown sections defined by the user.</p>
</li>
<li>
<p>Tear down the data bindings and models for this test.</p>
</li>
</ol>
<p>An important difference between JUnit and EUnit is that setup is split into two parts: model setup and regular setup. This split allows users to add code before and after model bindings are applied. Normally, the model setup sections will load all the models needed by the test suite, and the regular setup sections will further prepare the models selected by the model binding. Explicit teardown sections are usually not needed, as models are disposed automatically by EUnit. EUnit includes them for consistency with the xUnit frameworks.</p>
<p>Due to its focus on model management, model setup in EUnit is very flexible. Developers can combine several ways to set up models, such as model references, individual Apache Ant tasks, Apache Ant targets or <a href="../hutn">Human-Usable Text Notation (HUTN)</a> fragments.</p>
<p>A test case may produce one among several results. <code>SUCCESS</code> is obtained if all assertions passed and no exceptions were thrown. <code>FAILURE</code> is obtained if an assertion failed. <code>ERROR</code> is obtained if an unexpected exception was thrown while running the test. Finally, tests may be <code>SKIPPED</code> by the user.</p>
<h2 id="test-specification">Test Specification<a class="headerlink" href="#test-specification" title="Permanent link">&para;</a></h2>
<p>In the previous section, we described how test suites and test cases are organized. In this section, we will show how to write them.</p>
<p>As discussed before, after evaluating several approaches, we decided to combine the expressive power of EOL and the extensibility of Apache Ant. For this reason, EUnit test suites are split into two files: an Ant buildfile and an EOL script with some special-purpose annotations. The next subsections describe the contents of these two files and revisit the previous example with EUnit.</p>
<h3 id="ant-buildfile">Ant Buildfile<a class="headerlink" href="#ant-buildfile" title="Permanent link">&para;</a></h3>
<p>EUnit uses standard Ant buildfiles: running EUnit is as simple as using its Ant task. Users may run EUnit more than once in a single Ant launch: the graphical user interface will automatically aggregate the results of all test suites.</p>
<h4 id="eunit-invocations">EUnit Invocations<a class="headerlink" href="#eunit-invocations" title="Permanent link">&para;</a></h4>
<p>An example invocation of the EUnit Ant task using the most common features is shown in the listing below. Users will normally only use some of these features at a time, though. Optional attributes have been listed between brackets. Some nested elements can be repeated 0+ times (<code>*</code>) or 0-1 times (<code>?</code>). Valid alternatives for an attribute are separated with <code>|</code>.</p>
<div class="highlight"><pre><span></span><code><span class="nt">&lt;epsilon.eunit</span> <span class="na">src=</span><span class="s">&quot;...&quot;</span>
<span class="err">[</span><span class="na">failOnErrors=</span><span class="s">&quot;...&quot;</span><span class="err">]</span>
<span class="err">[</span><span class="na">package=</span><span class="s">&quot;..&quot;</span><span class="err">]</span>
<span class="err">[</span><span class="na">toDir=</span><span class="s">&quot;...&quot;</span><span class="err">]</span>
<span class="err">[</span><span class="na">report=</span><span class="s">&quot;yes|no&quot;</span><span class="err">]</span><span class="nt">&gt;</span>
(<span class="nt">&lt;model</span> <span class="na">ref=</span><span class="s">&quot;OldName&quot;</span> <span class="err">[</span><span class="na">as=</span><span class="s">&quot;NewName&quot;</span><span class="err">]</span><span class="nt">/&gt;</span>)*
(<span class="nt">&lt;uses</span> <span class="na">ref=</span><span class="s">&quot;x&quot;</span> <span class="err">[</span><span class="na">as=</span><span class="s">&quot;y&quot;</span><span class="err">]</span> <span class="nt">/&gt;</span>)*
(<span class="nt">&lt;exports</span> <span class="na">ref=</span><span class="s">&quot;z&quot;</span> <span class="err">[</span><span class="na">as=</span><span class="s">&quot;w&quot;</span><span class="err">]</span> <span class="nt">/&gt;</span>)*
(<span class="nt">&lt;parameter</span> <span class="na">name=</span><span class="s">&quot;myparam&quot;</span> <span class="na">value=</span><span class="s">&quot;myvalue&quot;</span> <span class="nt">/&gt;</span>)*
(<span class="nt">&lt;modelTasks&gt;</span><span class="c">&lt;!-- Zero or more Ant tasks --&gt;</span><span class="nt">&lt;/modelTasks&gt;</span>)?
<span class="nt">&lt;/epsilon.eunit&gt;</span>
</code></pre></div>
<p>The EUnit Ant task is based on the Epsilon abstract executable module task, inheriting some useful features. The attribute <code>src</code> points to the path of the EOL file, and the optional attribute <code>failOnErrors</code> can be set to false to prevent EUnit from aborting the Ant launch if a test case fails. EUnit also inherits support for importing and exporting global variables through the <code>&lt;uses&gt;</code> and <code>&lt;exports&gt;</code> elements: the original name is set in <code>ref</code>, and the optional <code>as</code> attribute allows for using a different name. For receiving parameters as name-value piars, the <code>&lt;parameter&gt;</code> element can be used.</p>
<p>Model references (using the <code>&lt;model&gt;</code> nested element) are also inherited from the Epsilon abstract executable module task. These allow model management tasks to refer by name to models previously loaded in the Ant buildfile. However, EUnit implicitly reloads the models after each test case. This ensures that test cases are isolated from each other.</p>
<p>The EUnit Ant task adds several new features to customize the test result reports and perform more advanced model setup. By default, EUnit generates reports in the XML format of the Ant <code>&lt;junit&gt;</code> task. This format is also used by many other tools, such as the TestNG unit testing framework, the Jenkins continuous integration server or the JUnit Eclipse plug-ins. To suppress these reports, report must be set to no.</p>
<p>By default, the XML report is generated in the same directory as the Ant buildfile, but it can be changed with the <code>toDir</code> attribute. Test names in JUnit are formed by its Java package, class and method: EUnit uses the filename of the EOL script as the class and the name of the EOL operation as the method. By default, the package is set to the string "default": users are encouraged to customize it with the <code>package</code> attribute.
The optional <code>&lt;modelTasks&gt;</code> nested element contains a sequence of Ant tasks which will be run after reloading the model references and before running the model setup sections in the EOL file. This allows users to run workflows more advanced than simply reloading model references.</p>
<h4 id="helper-targets">Helper Targets<a class="headerlink" href="#helper-targets" title="Permanent link">&para;</a></h4>
<p>Ant buildfiles for EUnit may include <em>helper targets</em>. These targets can be invoked using from anywhere in the EOL script. Helper targets are quite versatile: called from an EOL model setup section, they allow for reusing model loading fragments between different EUnit test suites. They can also be used to invoke the model management tasks under test. </p>
<!--Listing [\[lst:eunit-ex1-ant\]](#lst:eunit-ex1-ant){reference-type="ref"reference="lst:eunit-ex1-ant"} shows a helper target for an ETL transformation, and listing [\[lst:eunit-atl\]](#lst:eunit-atl){reference-type="ref"reference="lst:eunit-atl"} shows a helper target for an ATL transformation.-->
<h3 id="eol-script">EOL script<a class="headerlink" href="#eol-script" title="Permanent link">&para;</a></h3>
<p>The Epsilon Object Language script is the second half of the EUnit test suite. EOL annotations are used to tag some of the operations as data binding definitions (<code>@data</code> or <code>@Data</code>), additional model setup sections (<code>@model</code>/<code>@Model</code>), test setup and teardown sections (<code>@setup</code>/<code>@Before</code> and <code>@teardown</code>/<code>@After</code>) and test cases (<code>@test</code>/<code>@Test</code>). Suite setup and teardown sections can also be defined with <code>@suitesetup</code>/<code>@BeforeClass</code> and <code>@suiteteardown</code>/<code>@AfterClass</code> annotations: these operations will be run before and after all tests, respectively.</p>
<h4 id="data-bindings">Data bindings<a class="headerlink" href="#data-bindings" title="Permanent link">&para;</a></h4>
<p>Data bindings repeat all test cases with different values in some variables. To define a data binding, users must define an operation which returns a sequence of elements and is marked with @data variable. All test cases will be repeated once for each element of the returned sequence, setting the specified variable to the corresponding element. Listing 15.2 shows two nested data bindings and a test case which will be run four times: with x=1 and y=5, x=1 and y=6, x=2 and y=5 and finally x=2 and y=6. The example shows how x and y could be used by the setup section to generate an input model for the test. This can be useful if the intent of the test is ensuring that a certain property holds in a class of models, rather than a single model.</p>
<pre class="prettyprint lang-eol"><code>@data x
operation firstLevel() { return 1.to(2); }
@data y
operation secondLevel() { return 5.to(6); }
@setup
operation generateModel() { /* generate model using x and y */ }
@test
operation mytest() { /* test with the generated model */ }</code></pre>
<p>Alternatively, if both x and y were to use the same sets of values, we could add two @data annotations to the same operation. For instance, the listing below shows how we could test with 4 cases: x=1 and y=1, x=1 and y=2, x=2 and y=1 and x=2 and y=2.</p>
<pre class="prettyprint lang-eol"><code>@data x
@data y
operation levels() { return 1.to(2); }
@setup
operation generateModel() { /* generate model using x and y */ }
@test
operation mytest() { /* test with the generated model */ }</code></pre>
<h4 id="model-bindings">Model bindings<a class="headerlink" href="#model-bindings" title="Permanent link">&para;</a></h4>
<p>Model bindings repeat a test case with different subsets of models. They can be defined by annotating a test case with <code>$with map</code> or <code>$onlyWith map</code> one or more times, where map is an EOL expression that produces a <code>MAP</code>. For each key-value pair <code>key = value</code>, EUnit will rename the model named <code>value</code> to <code>key</code>. The difference between <code>$with</code> and <code>$onlyWith</code> is how they handle the models not mentioned in the <code>MAP</code>: <code>$with</code> will preserve them as is, and <code>$onlyWith</code> will make them unavailable during the test. <code>$onlyWith</code> is useful for tightly restricting the set of available models in a test and for avoiding ambiguous type references when handling multiple models using the same metamodel.</p>
<p>The listing below shows two tests which will be each run twice. The first test uses <code>$with</code>, which preserves models not mentioned in the MAP: the first time, model "A" will be the default model and model "B" will be the "Other" model, and the second time, model "B" will be the default model and model "A" will be the "Other" model. The second test uses two <code>$onlyWith</code> annotations: on the first run, "A" will be available as "Model" and "B" will not unavailable, and on the second run, only "B" will be available as "Model" and "A" will be unavailable.</p>
<pre class="prettyprint lang-eol"><code>$with Map {"" = "A", "Other" = "B"}
$with Map {"" = "B", "Other" = "A"}
@test
operation mytest() {
/* use the default and Other models, while
keeping the rest as is */
}
$onlyWith Map { "Model" = "A" }
$onlyWith Map { "Model" = "B" }
@test
operation mytest2() {
// first time: A as 'Model', B is unavailable
// second time: B as 'Model', A is unavailable
}</code></pre>
<h4 id="additional-variables-and-built-in-operations">Additional variables and built-in operations<a class="headerlink" href="#additional-variables-and-built-in-operations" title="Permanent link">&para;</a></h4>
<p>EUnit provides several variables and operations which are useful for testing. These are listed in the table below.</p>
<table>
<thead>
<tr>
<th>Signature</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>runTarget(name : String)</td>
<td>Runs the specified target of the Ant buildfile which invoked EUnit.</td>
</tr>
<tr>
<td>exportVariable(name : String)</td>
<td>Exports the specified variable, to be used by another executable module.</td>
</tr>
<tr>
<td>useVariable(name : String)</td>
<td>Imports the specified variable, which should have been previously exported by another executable module.</td>
</tr>
<tr>
<td>loadHutn(name : String, hutn : String)</td>
<td>Loads an EMF model with the specified name, by parsing the second argument as an HUTN fragment.</td>
</tr>
<tr>
<td>antProject : org.apache.tools.ant.Project</td>
<td>Global variable which refers to the Ant project being executed. This can be used to create and run Ant tasks from inside the EOL code.</td>
</tr>
</tbody>
</table>
<h4 id="assertions">Assertions<a class="headerlink" href="#assertions" title="Permanent link">&para;</a></h4>
<p>EUnit implements some common assertions for equality and inequality,
with special versions for comparing floating-point numbers. EUnit also
supports a limited form of exception testing with , which checks that
the expression inside it throws an exception. Custom assertions can be
defined by the user with the operation, which fails a test with a custom
message. The available assertions are shown in
the table below.</p>
<table>
<thead>
<tr>
<th>Signature</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>assertEqualDirectories(expectedPath : String,obtainedPath : String)</td>
<td>Fails the test if the contents of the directory in differ from those of the directory in . Directory comparisons are performed on recursive snapshots of both directories.</td>
</tr>
<tr>
<td>assertEqualFiles(expectedPath : String,obtainedPath : String)</td>
<td>Fails the test if the contents of the file in differ from those of the file in . File comparisons are performed on snapshots of both files.</td>
</tr>
<tr>
<td>assertEqualModels([msg : String,]expectedModel : String,obtainedModel : String[, options : Map])</td>
<td>Fails the test with the optional message if the model named is not equal to the model named . Model comparisons are performed on snapshots of the resource sets of both models. During EMF comparisons, XMI identifiers are ignored. Additional comparator-specific options can be specified through .</td>
</tr>
<tr>
<td>assertEquals([msg : String,]expected : Any,obtained : Any)</td>
<td>Fails the test with the optional message if the values of and are not equal.</td>
</tr>
<tr>
<td>assertEquals([msg : String,]expected : Real,obtained : Real,ulps : Integer)</td>
<td>Fails the test with the optional message if the values of and differ in more than units of least precision. See <a href="http://download.oracle.com/javase/6/docs/api/java/lang/Math.html#ulp(double)">this site</a> for details.</td>
</tr>
<tr>
<td>assertError(expr : Any)</td>
<td>Fails the test if no exception is thrown during the evaluation of .</td>
</tr>
<tr>
<td>assertFalse([msg : String,]cond : Boolean)</td>
<td>Fails the test with the optional message if is . It is a negated version of assertTrue.</td>
</tr>
<tr>
<td>assertLineWithMatch([msg : String,]path : String,regexp : String)</td>
<td>Fails the test with the optional message if the file at does not have a line containing a substring matching the regular expression <sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup>.</td>
</tr>
<tr>
<td>assertMatchingLine([msg : String,]path : String,regexp : String)</td>
<td>Fails the test with the optional message if the file at does not have a line that matches the regular expression <sup id="fnref:3"><a class="footnote-ref" href="#fn:3">3</a></sup> from start to finish.</td>
</tr>
<tr>
<td>assertNotEqualDirectories(expectedPath : String,obtainedPath : String)</td>
<td>Negated version of assertEqualDirectories.</td>
</tr>
<tr>
<td>assertNotEqualFiles(expectedPath : String,obtainedPath : String)</td>
<td>Negated version of assertEqualFiles.</td>
</tr>
<tr>
<td>assertNotEqualModels([msg : String,]expectedModel : String,obtainedModel : String)</td>
<td>Negated version of assertNotEqualModels.</td>
</tr>
<tr>
<td>assertNotEquals([msg : String,]expected : Any,obtained : Any)</td>
<td>Negated version of assertEquals([msg : String,] expected : Any, obtained : Any).</td>
</tr>
<tr>
<td>assertNotEquals([msg : String,]expected : Real,obtained : Real,ulps : Integer)</td>
<td>Negated version of assertEquals([msg : String,] expected : Real, obtained : Real, ulps : Integer).</td>
</tr>
<tr>
<td>assertTrue([msg : String,]cond : Boolean)</td>
<td>Fails the test with the optional message if is .</td>
</tr>
<tr>
<td>fail(msg : String)</td>
<td>Fails a test with the message .</td>
</tr>
</tbody>
</table>
<p>The table below lists the available option keys which can be used with the model equality assertions, by comparator.</p>
<table>
<thead>
<tr>
<th>Comparator and Key</th>
<th>Usage</th>
</tr>
</thead>
<tbody>
<tr>
<td>EMF, "whitespace"</td>
<td>When set to "ignore", differences in EString attribute values due to whitespace will be ignored. Disabled by default.</td>
</tr>
<tr>
<td>EMF, "ignoreAttributeValueChanges"</td>
<td>Can contain a of strings of the form "package.class.attribute". Differences in the values for these attributes will be ignored. However, if the attribute is set on one side and not on the other, the difference will be reported as normal. Empty by default.</td>
</tr>
<tr>
<td>EMF, "unorderedMoves"</td>
<td>When set to "ignore", differences in the order of the elements within an unordered EReference. Enabled by default.</td>
</tr>
</tbody>
</table>
<p>More importantly, EUnit implements specific assertions for comparing models, files and trees of files. Model comparison is not implemented by the assertions themselves: it is an optional service implemented by some EMC drivers. Currently, EMF models will automatically use EMF Compare as their comparison engine. The rest of the EMC drivers do not support comparison yet. The main advantage of having an abstraction layer implement model comparison as a service is that the test case definition is decoupled from the concrete model comparison engine used.</p>
<p>Model, file and directory comparisons take a snapshot of their operands before comparing them, so EUnit can show the differences right at the moment when the comparison was performed. This is especially important when some of the models are generated on the fly by the EUnit test suite, or when a test case for code generation may overwrite the results of the previous one.</p>
<p>The following figure shows a screenshot of the EUnit graphical user interface. On the left, an Eclipse view shows the results of several EUnit test suites. We can see that the <code>load- models-with-hutn</code> suite failed. The Compare button to the right of "Failure Trace" can be pressed to show the differences between the expected and obtained models, as shown on the right side. EUnit implements a pluggable architecture where <em>difference viewers</em> are automatically selected based on the types of the operands. There are difference viewers for EMF models, file trees and a fallback viewer which converts both operands to strings.</p>
<p><img alt="image" src="../images/EUnitUI.png" /></p>
<h2 id="examples">Examples<a class="headerlink" href="#examples" title="Permanent link">&para;</a></h2>
<h3 id="models-and-tasks-in-the-buildfile">Models and Tasks in the Buildfile<a class="headerlink" href="#models-and-tasks-in-the-buildfile" title="Permanent link">&para;</a></h3>
<p>After describing the basic syntax, we will show how to use EUnit to test an ETL transformation.</p>
<p>The Ant buildfile is shown in the listing below. It has two targets: <code>run-tests</code> (lines 2-19) invokes the EUnit suite, and <code>tree2graph</code> (lines 23-28) is a helper target which transforms model <code>Tree</code> into model <code>Graph</code> using ETL. The <code>&lt;modelTasks&gt;</code> nested element is used to load the input, expected output and output EMF models. <code>Graph</code> is loaded with <code>read</code> set to <code>false</code>: the model will be initially empty, and will be populated by the ETL transformation.</p>
<div class="highlight"><pre><span></span><code><span class="nt">&lt;project&gt;</span>
<span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;run-tests&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;epsilon.eunit</span> <span class="na">src=</span><span class="s">&quot;test-external.eunit&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;modelTasks&gt;</span>
<span class="nt">&lt;epsilon.emf.loadModel</span> <span class="na">name=</span><span class="s">&quot;Tree&quot;</span>
<span class="na">modelfile=</span><span class="s">&quot;tree.model&quot;</span>
<span class="na">metamodelfile=</span><span class="s">&quot;tree.ecore&quot;</span>
<span class="na">read=</span><span class="s">&quot;true&quot;</span> <span class="na">store=</span><span class="s">&quot;false&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;epsilon.emf.loadModel</span> <span class="na">name=</span><span class="s">&quot;GraphExpected&quot;</span>
<span class="na">modelfile=</span><span class="s">&quot;graph.model&quot;</span>
<span class="na">metamodelfile=</span><span class="s">&quot;graph.ecore&quot;</span>
<span class="na">read=</span><span class="s">&quot;true&quot;</span> <span class="na">store=</span><span class="s">&quot;false&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;epsilon.emf.loadModel</span> <span class="na">name=</span><span class="s">&quot;Graph&quot;</span>
<span class="na">modelfile=</span><span class="s">&quot;transformed.model&quot;</span>
<span class="na">metamodelfile=</span><span class="s">&quot;graph.ecore&quot;</span>
<span class="na">read=</span><span class="s">&quot;false&quot;</span> <span class="na">store=</span><span class="s">&quot;false&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/modelTasks&gt;</span>
<span class="nt">&lt;/epsilon.eunit&gt;</span>
<span class="nt">&lt;/target&gt;</span>
<span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;tree2graph&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;epsilon.etl</span> <span class="na">src=</span><span class="s">&quot;${basedir}/resources/Tree2Graph.etl&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;model</span> <span class="na">ref=</span><span class="s">&quot;Tree&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;model</span> <span class="na">ref=</span><span class="s">&quot;Graph&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/epsilon.etl&gt;</span>
<span class="nt">&lt;/target&gt;</span>
<span class="nt">&lt;/project&gt;</span>
</code></pre></div>
<p>The EOL script is shown in the listing below: it invokes the helper task (line 3) and checks that the obtained model is equal to the expected model (line 4). Internally, EMC will perform the comparison using EMF Compare.</p>
<pre class="prettyprint lang-eol"><code>@test
operation transformationWorksAsExpected() {
runTarget("tree2graph");
assertEqualModels("GraphExpected", "Graph");
}</code></pre>
<h3 id="models-and-tasks-in-the-eol-script">Models and Tasks in the EOL Script<a class="headerlink" href="#models-and-tasks-in-the-eol-script" title="Permanent link">&para;</a></h3>
<p>In the previous section, the EOL file is kept very concise because the model setup and model management tasks under test were specified in the Ant buildfile. In this section, we will inline the models and the tasks into the EOL script instead.</p>
<p>The Ant buildfile is shown in the listing below. It is now very simple: all it needs to do is run the EOL script. However, since we will parse HUTN in the EOL script, we must make sure the s of the metamodels are registered.</p>
<div class="highlight"><pre><span></span><code><span class="nt">&lt;project&gt;</span>
<span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;run-tests&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;epsilon.emf.register</span> <span class="na">file=</span><span class="s">&quot;tree.ecore&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;epsilon.emf.register</span> <span class="na">file=</span><span class="s">&quot;graph.ecore&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;epsilon.eunit</span> <span class="na">src=</span><span class="s">&quot;test-inlined.eunit&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/target&gt;</span>
<span class="nt">&lt;/project&gt;</span>
</code></pre></div>
<p>The EOL script used is shown below. Instead of loading models through the Ant tasks, the <code>loadHutn</code> operation has been used to load the models. The test itself is almost the same, but instead of running a helper target, it invokes an operation which creates and runs the ETL Ant task through the <code>antProject</code> variable provided by EUnit, taking advantage of the support in EOL for invoking Java code through reflection.</p>
<pre class="prettyprint lang-eol"><code>@model
operation loadModels() {
loadHutn("Tree", '@Spec {Metamodel {nsUri: "Tree" }}
Model {
Tree "t1" { label : "t1" }
Tree "t2" {
label : "t2"
parent : Tree "t1"
}
}
');
loadHutn("GraphExpected", '@Spec {Metamodel {nsUri: "Graph"}}
Graph { nodes :
Node "t1" {
name : "t1"
outgoing : Edge { source : Node "t1" target : Node "t2" }
},
Node "t2" {
name : "t2"
}
}
');
loadHutn("Graph", '@Spec {Metamodel {nsUri: "Graph"}}');
}
@test
operation transformationWorksAsExpected() {
runETL();
assertEqualModels("GraphExpected", "Graph");
}
operation runETL() {
var etlTask := antProject.createTask("epsilon.etl");
etlTask.setSrc(new Native('java.io.File')(
antProject.getBaseDir(), 'resources/etl/Tree2Graph.etl'));
etlTask.createModel().setRef("Tree");
etlTask.createModel().setRef("Graph");
etlTask.execute();
}</code></pre>
<h2 id="extending-eunit">Extending EUnit<a class="headerlink" href="#extending-eunit" title="Permanent link">&para;</a></h2>
<p>EUnit is based on the Epsilon platform, but it is designed to accommodate other technologies. In this section we will explain several strategies to add support for these technologies to EUnit.</p>
<p>EUnit uses the Epsilon Model Connectivity abstraction layer to handle different modelling technologies. Adding support for a different modelling technology only requires implementing another driver for EMC. Depending on the modelling technology, the driver can provide optional services such as model comparison, caching or reflection.</p>
<p>EUnit uses Ant as a workflow language: all model management tasks must be exposed through Ant tasks. It is highly encouraged, however, that the Ant task is aware of the EMC model repository linked to the Ant project. Otherwise, users will have to shuffle the models out from and back into the repository between model management tasks. As an example, a helper target for an ATL transformation with the existing Ant tasks needs to:</p>
<ol>
<li>Save the input model in the EMC model repository to a file, by invoking the <code>&lt;epsilon.storeModel&gt;</code> task.</li>
<li>Load the metamodels and the input model with <code>&lt;atl.loadModel&gt;</code>.</li>
<li>Run the ATL transformation with <code>&lt;atl.launch&gt;</code>.</li>
<li>Save the result of the ATL transformation with <code>&lt;atl.saveModel&gt;</code>.</li>
<li>Load it into the EMC model repository with <code>&lt;epsilon.emf.loadModel&gt;</code>.</li>
</ol>
<p>The listing below shows the Ant buildfile which would be required for running these steps, showing that while EUnit can use the existing ATL tasks as-is, the required helper task is quite longer than the one shown above. Ideally, Ant tasks should be adapted or wrapped to use models directly from the EMC model repository.</p>
<div class="highlight"><pre><span></span><code><span class="nt">&lt;project&gt;</span>
<span class="c">&lt;!-- ... omitted ... --&gt;</span>
<span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;atl&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- Create temporary files for input and output models --&gt;</span>
<span class="nt">&lt;tempfile</span> <span class="na">property=</span><span class="s">&quot;atl.temp.srcfile&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;tempfile</span> <span class="na">property=</span><span class="s">&quot;atl.temp.dstfile&quot;</span> <span class="nt">/&gt;</span>
<span class="c">&lt;!-- Save input model to a file --&gt;</span>
<span class="nt">&lt;epsilon.storeModel</span> <span class="na">model=</span><span class="s">&quot;Tree&quot;</span>
<span class="na">target=</span><span class="s">&quot;${atl.temp.srcfile}&quot;</span> <span class="nt">/&gt;</span>
<span class="c">&lt;!-- Load the metamodels and the source model --&gt;</span>
<span class="nt">&lt;atl.loadModel</span> <span class="na">name=</span><span class="s">&quot;TreeMM&quot;</span> <span class="na">metamodel=</span><span class="s">&quot;MOF&quot;</span>
<span class="na">path=</span><span class="s">&quot;metamodels/tree.ecore&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;atl.loadModel</span> <span class="na">name=</span><span class="s">&quot;GraphMM&quot;</span> <span class="na">metamodel=</span><span class="s">&quot;MOF&quot;</span>
<span class="na">path=</span><span class="s">&quot;metamodels/graph.ecore&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;atl.loadModel</span> <span class="na">name=</span><span class="s">&quot;Tree&quot;</span> <span class="na">metamodel=</span><span class="s">&quot;TreeMM&quot;</span>
<span class="na">path=</span><span class="s">&quot;${atl.temp.srcfile}&quot;</span> <span class="nt">/&gt;</span>
<span class="c">&lt;!-- Run ATL and save the model --&gt;</span>
<span class="nt">&lt;atl.launch</span> <span class="na">path=</span><span class="s">&quot;transformation/tree2graph.atl&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;inmodel</span> <span class="na">name=</span><span class="s">&quot;IN&quot;</span> <span class="na">model=</span><span class="s">&quot;Tree&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;outmodel</span> <span class="na">name=</span><span class="s">&quot;OUT&quot;</span> <span class="na">model=</span><span class="s">&quot;Graph&quot;</span> <span class="na">metamodel=</span><span class="s">&quot;GraphMM&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/atl.launch&gt;</span>
<span class="nt">&lt;atl.saveModel</span> <span class="na">model=</span><span class="s">&quot;Graph&quot;</span> <span class="na">path=</span><span class="s">&quot;${atl.temp.dstfile}&quot;</span> <span class="nt">/&gt;</span>
<span class="c">&lt;!-- Load it back into the EUnit suite --&gt;</span>
<span class="nt">&lt;epsilon.emf.loadModel</span> <span class="na">name=</span><span class="s">&quot;Graph&quot;</span>
<span class="na">modelfile=</span><span class="s">&quot;${atl.temp.dstfile}&quot;</span>
<span class="na">metamodeluri=</span><span class="s">&quot;Graph&quot;</span>
<span class="na">read=</span><span class="s">&quot;true&quot;</span> <span class="na">store=</span><span class="s">&quot;false&quot;</span> <span class="nt">/&gt;</span>
<span class="c">&lt;!-- Delete temporary files --&gt;</span>
<span class="nt">&lt;delete</span> <span class="na">file=</span><span class="s">&quot;${atl.temp.srcfile}&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;delete</span> <span class="na">file=</span><span class="s">&quot;${atl.temp.dstfile}&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/target&gt;</span>
<span class="nt">&lt;/project&gt;</span>
</code></pre></div>
<p>Another advantage in making model management tasks EMC-aware is that they can easily “export” their results as models, making them easier to test. For instance, the EVL Ant task allows for exporting its results as a model by setting the attribute <code>exportAsModel</code> to <code>true</code>. This way, EOL can query the results as any regular model. This is simpler than transforming the validated model to a problem metamodel. The example in the listing below checks that a single warning was produced due to the expected rule (<code>LabelsStartWithT</code>) and the expected model element.</p>
<pre class="prettyprint lang-eol"><code>@test
operation valid() {
var tree := new Tree!Tree;
tree.label := '1n';
runTarget('validate-tree');
var errors := EVL!EvlUnsatisfiedConstraint.allInstances;
assertEquals(1, errors.size);
var error := errors.first;
assertEquals(tree, error.instance);
assertEquals(false, error.constraint.isCritique);
assertEquals('LabelsStartWithT', error.constraint.name);
}</code></pre>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>CPU time only measures the time elapsed in the thread used by EUnit, and is more stable with varying system load in single-threaded programs.&#160;<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:2">
<p>See <code>JAVA.UTIL.REGEX.PATTERN</code> for details about the accepted syntax for regular expressions.&#160;<a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
<li id="fn:3">
<p>See footnote <code>assertLineWithMatch</code> for details about the syntax of the regular expressions.&#160;<a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text">&#8617;</a></p>
</li>
</ol>
</div>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../emg/" title="Model generation (EMG)" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Model generation (EMG)
</span>
</div>
</a>
<a href="../pinset/" title="Dataset extraction (Pinset)" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Dataset extraction (Pinset)
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright © Eclipse Foundation, Inc. All Rights Reserved.
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">Material for MkDocs</a>
</div>
<div class="md-footer-copyright epsilon-eclipse-links">
<ul>
<li><a href="https://www.eclipse.org/legal/privacy.php">Privacy Policy</a></li>
<li><a href="https://www.eclipse.org/legal/termsofuse.php">Terms of Use</a></li>
<li><a href="https://www.eclipse.org/legal/copyright.php">Copyright Agent</a></li>
</ul>
</div>
</div>
</div>
</footer>
</div>
<script src="../../assets/javascripts/vendor.c3dc8c49.min.js"></script>
<script src="../../assets/javascripts/bundle.f9edbbd5.min.js"></script><script id="__lang" type="application/json">{"clipboard.copy": "Copy to clipboard", "clipboard.copied": "Copied to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.result.placeholder": "Type to start searching", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents"}</script>
<script>
app = initialize({
base: "../..",
features: [],
search: Object.assign({
worker: "../../assets/javascripts/worker/search.8e2cddea.min.js"
}, typeof search !== "undefined" && search)
})
</script>
<script src="https://unpkg.com/mermaid@8.5.1/dist/mermaid.min.js"></script>
<script src="../../assets/javascript/mermaid.js"></script>
<script src="../../assets/javascript/jquery.js"></script>
<script src="../../assets/javascript/google-code-prettify/prettify.js"></script>
<script src="../../assets/javascript/google-code-prettify/lang-emfatic.js"></script>
<script src="../../assets/javascript/google-code-prettify/lang-epsilon.js"></script>
<script src="../../assets/javascript/google-code-prettify/prettyprint.js"></script>
</body>
</html>