diff --git a/kattcmd/commands/run.py b/kattcmd/commands/run.py
index bd17f58a7039c4d83186b42bc57ee925bdf59459..9ba51dadc3f21d85d44271b347dfdc546bda3e6e 100644
--- a/kattcmd/commands/run.py
+++ b/kattcmd/commands/run.py
@@ -4,7 +4,7 @@ import click
 
 
 def RunPythonAgainstTests(bus, inputs, problemname):
-    '''Run python program against given inputs and return subprocesses/errors.'''
+    '''Run python program against given inputs and return output/errors.'''
     home = bus.call('kattcmd:find-root', bus)
     executable = os.path.join(home, 'build', problemname, problemname + '.py')
 
@@ -39,6 +39,41 @@ def RunPythonAgainstTests(bus, inputs, problemname):
     return processes
 
 
+def RunCppAgainstTests(bus, inputs, problemname):
+    '''Run c++ against given inputs and return outpu/errors.'''
+    home = bus.call('kattcmd:find-root', bus)
+    executable = os.path.join(home, 'build', problemname, problemname)
+
+    if not os.path.exists(executable):
+        bus.call('kattcmd:run:no-executable', problemname, 'cpp')
+        return
+
+    timeout = bus.call('kattcmd:config:load-user', bus, 'default-timeout')
+    timeout = timeout or bus.call('kattcmd:config:load-repo', bus, 'default-timeout')
+    timeout = int(timeout or '10')
+
+    def RunSingleInput(inputfile):
+        abspath = os.path.abspath(inputfile)
+        command = '{} < {}'.format(os.path.abspath(executable), abspath)
+        try:
+            output = subprocess.check_output(
+                command,
+                timeout=timeout,
+                shell=True
+            )
+            if isinstance(output, bytes):
+                output = output.decode('utf-8')
+            return output
+        except subprocess.TimeoutExpired as e:
+            return e
+        except subprocess.CalledProcessError as e:
+            return e
+
+    processes = [RunSingleInput(inputfile) for inputfile in inputs]
+    bus.call('kattcmd:run:executed', problemname, 'cpp', inputs, processes)
+    return processes
+
+
 def Init(bus):
 
     def OnNoExecutable(problemname, executable_type):
@@ -48,6 +83,8 @@ def Init(bus):
         '''Called when a problem has been executed and finished.'''
 
     bus.provide('kattcmd:run:python', RunPythonAgainstTests)
+    bus.provide('kattcmd:run:cpp', RunCppAgainstTests)
     bus.provide('kattcmd:run:no-executable', OnNoExecutable)
     bus.provide('kattcmd:run:executed', OnExecuted)
 
+
diff --git a/kattcmd/commands/submit.py b/kattcmd/commands/submit.py
index ed99c051474d7381edf1e45933cb0b0d5e6e23c3..1970522123ca54b02c46005aaba740649e613c79 100644
--- a/kattcmd/commands/submit.py
+++ b/kattcmd/commands/submit.py
@@ -100,6 +100,30 @@ def SubmitPythonProblem(bus, problemname):
     bus.call('kattcmd:submit:submitted', submit_response)
     return submit_response
 
+
+def SubmitCppProblem(bus, problemname):
+    '''Submits a cpp problem to kattis.'''
+
+    response = _Login(bus)
+    if response.status_code != 200:
+        bus.call('kattcmd:submit:bad-login-response', response)
+        return
+
+    extensions = ['.cc', '.cpp', '.cxx', '.h', '.hh', '.hpp', '.hxx']
+    files = _GetFilesWithExtensions(bus, problemname, extensions)
+    language = 'C++'
+    submiturl = _GetUserConfig(bus).get('kattis', 'submissionurl')
+    submit_response = _Submit(submiturl, response.cookies, language,
+                              problemname, files, problemname)
+
+    if submit_response.status_code != 200:
+        bus.call('kattcmd:submit:bad-submit-response', submit_response)
+        return
+
+    bus.call('kattcmd:submit:submitted', submit_response)
+    return submit_response
+
+
 def Init(bus):
 
     def OnBadLoginResponse(response):
@@ -115,6 +139,7 @@ def Init(bus):
     bus.provide('kattcmd:submit:bad-login-response', OnBadLoginResponse)
     bus.provide('kattcmd:submit:bad-submit-response', OnBadSubmitResponse)
     bus.provide('kattcmd:submit:submitted', OnSubmitted)
+    bus.provide('kattcmd:submit:cpp', SubmitCppProblem)
 
 
 def CLI(bus, parent):
@@ -141,25 +166,32 @@ def CLI(bus, parent):
         problemurl = '{}/submissions/{}'.format(host, ids[0])
         click.launch(problemurl)
 
+    def OnNoFiles(problemname):
+        click.secho('Could not find any files for "{}"!'.format(problemname), fg='red')
+        click.echo('Exiting')
+        exit(1)
 
     @parent.command()
     @click.argument('name')
-    @click.argument('language', default='python', type=click.Choice(['python', 'cpp']))
-    def submit(name, language):
+    def submit(name):
         '''Submits a problem to kattis.
 
         When you have implemented and tested a problem this command
         will upload it to kattis and then open the submission in your
-        browser. The language defaults to python and you must specify
-        which language your solution uses. Currently only supporting
-        'python' and 'cpp' (as in C++).
+        browser. It will look for the files you modified most recently
+        and use the language that is written in to determine what to
+        files to upload.
 
         '''
         bus.listen('kattcmd:submit:bad-login-response', OnBadLoginResponse)
         bus.listen('kattcmd:submit:bad-submit-response', OnBadSubmitResponse)
         bus.listen('kattcmd:submit:submitted', OnSubmitted)
+        bus.listen('kattcmd:latest:no-files', OnNoFiles)
 
+        language, _ = bus.call('kattcmd:latest', bus, name)
         if language == 'python':
             bus.call('kattcmd:submit:python', bus, name)
+        elif language == 'cpp':
+            bus.call('kattcmd:submit:cpp', bus, name)
         else:
             click.secho('Unsupported language!', fg='red')
diff --git a/kattcmd/commands/test.py b/kattcmd/commands/test.py
index 1af5b7b3827954938dd9906e8f87d5483a7907fe..48f1c6d91aa31d8bf496d6e9d2163981980650cb 100644
--- a/kattcmd/commands/test.py
+++ b/kattcmd/commands/test.py
@@ -75,6 +75,10 @@ def CLI(bus, parent):
         click.secho('Could not manage to find an executable for {}. Was looking for a {} file'.format(name, type), fg='red')
         exit(1)
 
+    def OnNoFiles(problemname):
+        click.secho('Could not find any files for problem "{}"'.format(problemname), fg='red')
+        click.echo('Exiting')
+        exit(1)
 
     @parent.command()
     @click.argument('name')
@@ -95,6 +99,7 @@ def CLI(bus, parent):
         bus.listen('kattcmd:compile:cpp-compiled', OnCppCompiled)
         bus.listen('kattcmd:compile:cpp-compile-failed', OnCppFailed)
         bus.listen('kattcmd:run:no-executable', OnNoExecutable)
+        bus.listen('kattcmd:latest:no-files', OnNoFiles)
 
         # Compile name under most appropriate language
         root = bus.call('kattcmd:find-root', bus)
@@ -103,23 +108,18 @@ def CLI(bus, parent):
             click.secho('Could not find problem with name: {}'.format(name), fg='red')
             return
 
-        cpp_endings = ['.cpp', '.cxx', '.cc']
-        directory = os.path.join(root, 'kattis', name)
-        items = os.listdir(directory)
-        if '{}.py'.format(name) in items:
-            files = bus.call('kattcmd:compile:python', bus, name)
-            topic = 'kattcmd:run:python'
-            args = [name]
-
-        elif any('{}{}'.format(name, ext) in items for ext in cpp_endings):
-            binary = bus.call('kattcmd:compile:cpp', bus, name)
-            binary = os.path.relpath(binary)
-            click.secho('Not implemented yet, but binary is compiled and at {}'.format(binary))
-            return
+        # TODO: below should use kattcmd:latest
+        language, _ = bus.call('kattcmd:latest', bus, name)
+        topic_mapping = {
+            'python': 'kattcmd:run:python',
+            'cpp': 'kattcmd:run:cpp'
+        }
 
-        else:
-            click.secho('Could not find main program to be either C++ or Python')
+        if not language in topic_mapping:
+            click.secho('Cannot run for language: {}'.format(language), fg='red')
             return
+
+        topic = topic_mapping[language]
         items = [os.path.join(directory, item) for item in items]
 
         # Find all test files
diff --git a/test/test_run.py b/test/test_run.py
index 7979cff1bf4b168829b068ced03efd04a04ab5cd..41cac7ec5621c8d4a8048ce857e60b81aa157584 100644
--- a/test/test_run.py
+++ b/test/test_run.py
@@ -10,6 +10,17 @@ a, b = map(int, sys.stdin.readline().split())
 print(b)
 """
 
+_CarrotsSolutionCpp = """
+#include <iostream>
+using namespace std;
+int main() {
+   int a;
+   cin >> a >> a;
+   cout << a << endl;
+   return 0;
+}
+"""
+
 @WithCustomCWD
 @WithMostModules
 def test_PythonRun(bus):
@@ -42,3 +53,39 @@ def test_PythonRun(bus):
     assert isinstance(output, str)
     assert output.strip() == "1"
 
+
+@WithCustomCWD
+@WithMostModules
+def test_CppRun(bus):
+    problemname = 'carrots'
+    calls = [
+        ('kattcmd:init', 'kattcmd:init:directory-created'),
+        ('kattcmd:open', 'kattcmd:open:problem-opened', [problemname])
+    ]
+    assert all(checker.yay for _, checker in ExecuteInOrder(bus, calls))
+
+    home = os.environ['HOME']
+    source_path = os.path.join(home, 'kattis', problemname, problemname + '.cpp')
+    with open(source_path, 'w') as f:
+        f.write(_CarrotsSolutionCpp)
+
+    calls = [
+        ('kattcmd:compile:cpp', 'kattcmd:compile:cpp-compiled', [problemname])
+    ]
+    assert all(checker.yay for _, checker in ExecuteInOrder(bus, calls))
+
+    home = os.environ['HOME']
+
+    inputfname = os.path.join(home, 'test1.in')
+    with open(inputfname, 'w') as f:
+        f.write("2 1")
+
+    checker = CallChecker()
+    bus.listen('kattcmd:run:executed', checker)
+    outputs = bus.call('kattcmd:run:cpp', bus, [inputfname], problemname)
+    assert checker.yay
+
+    assert len(outputs) == 1
+    output = outputs[0]
+    assert isinstance(output, str)
+    assert output.strip() == "1"
diff --git a/test/test_submit.py b/test/test_submit.py
index b54096541f5cd8b41eddd0f775072723395d2ed0..c1c528cde12d8d2fea2d26b2dd731cf71715a61c 100644
--- a/test/test_submit.py
+++ b/test/test_submit.py
@@ -10,6 +10,17 @@ a, b = map(int, sys.stdin.readline().split())
 print(b)
 """
 
+_CarrotsSolutionCpp = """
+#include <iostream>
+using namespace std;
+int main() {
+   int a;
+   cin >> a >> a;
+   cout << a << endl;
+   return 0;
+}
+"""
+
 def ShouldSkipSubmit():
     expected_envs = [
         'KATTIS_TOKEN',
@@ -83,3 +94,40 @@ def test_SubmitCarrotsWithPython(bus):
     assert result.text and isinstance(result.text, str)
     assert 'Submission ID:' in result.text
 
+
+@pytest.mark.submission
+@pytest.mark.skipif(ShouldSkipSubmit(), reason='No environment variables for running submit')
+@WithCustomCWD
+@WithMostModules
+def test_SubmitCarrotsWithCpp(bus):
+    SetupKattisRC()
+    problemname = 'carrots'
+    solution = _CarrotsSolutionCpp
+
+    # Init and open carrots problem
+    calls = [
+        ('kattcmd:init', 'kattcmd:init:directory-created'),
+        ('kattcmd:open', 'kattcmd:open:problem-opened', [problemname])
+    ]
+    assert all(checker.yay for _, checker in ExecuteInOrder(bus, calls))
+
+    # Create solution
+    home = bus.call('kattcmd:find-root', bus)
+    target = os.path.join(home, 'kattis', problemname, problemname + '.cpp')
+    with open(target, 'w') as f:
+        f.write(solution)
+
+    # Submit
+    calls = [
+        ('kattcmd:submit:cpp', 'kattcmd:submit:submitted', [problemname])
+    ]
+
+    results = list(ExecuteInOrder(bus, calls))
+    assert len(results) == 1
+
+    # Check call and that the text received from kattis is as expected
+    result, checker = results[0]
+    assert checker.yay
+    assert result.text and isinstance(result.text, str)
+    assert 'Submission ID:' in result.text
+