From 221430c0171efe84e902cf6fa0a4886d59d0f133 Mon Sep 17 00:00:00 2001 From: lesion Date: Thu, 18 Nov 2021 15:35:32 +0100 Subject: [PATCH] basic karma/mocha test suite setup --- .gitignore | 1 + karma.config.js | 34 ++++++ package.json | 34 ++++++ radiomanifest.js | 219 ++++++++++++++++++++++--------------- test/radiomanifest.test.js | 31 ++++++ 5 files changed, 229 insertions(+), 90 deletions(-) create mode 100644 .gitignore create mode 100644 karma.config.js create mode 100644 package.json create mode 100644 test/radiomanifest.test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/karma.config.js b/karma.config.js new file mode 100644 index 0000000..31246d2 --- /dev/null +++ b/karma.config.js @@ -0,0 +1,34 @@ +module.exports = function (config) { + config.set({ + frameworks: ['mocha'], + // plugins: ['karma-webpack', 'karma-mocha', 'karma-chai-as-promised'], + webpack: { + // karma watches the test entry points + // Do NOT specify the entry option + // webpack watches dependencies + + // webpack configuration + }, + preprocessors: { + 'test/**/*.js': ['webpack'], + 'radiomanifest.js': ['webpack'] + }, + files: [ + 'radiomanifest.js', + 'test/**/*.js' + ], + reporters: ['progress'], + port: 9876, // karma web server port + colors: true, + logLevel: config.LOG_INFO, + browsers: ['ChromeHeadless', 'FirefoxHeadless'], + autoWatch: false, + concurrency: Infinity, + customLaunchers: { + FirefoxHeadless: { + base: 'Firefox', + flags: ['-headless'], + }, + }, + }) +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..63fb6f1 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "radiomanifest", + "version": "0.1.0", + "description": "", + "main": "radiomanifest.js", + "directories": { + "test": "tests" + }, + "repository": { + "type": "git", + "url": "gogs@git.lattuga.net:lesion/radiomanifest.js.git" + }, + "scripts": { + "test": "npm run test:node && npm run test:browser", + "test:node": "mocha", + "test:browser": "karma start --single-run --browsers ChromeHeadless,FirefoxHeadless karma.config.js" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "chai": "^4.3.4", + "chai-as-promised": "^7.1.1", + "karma": "^6.3.9", + "karma-chrome-launcher": "^3.1.0", + "karma-firefox-launcher": "^2.1.2", + "karma-mocha": "^2.0.1", + "karma-webpack": "^5.0.0", + "mocha": "^9.1.3", + "webpack": "^5.64.1" + }, + "dependencies": { + "isomorphic-unfetch": "^3.1.0" + } +} diff --git a/radiomanifest.js b/radiomanifest.js index abb6bea..4c4d4ac 100644 --- a/radiomanifest.js +++ b/radiomanifest.js @@ -1,121 +1,160 @@ +const fetch = require('isomorphic-unfetch') +module.exports = { + + /** + * + * @param {String} baseURL to search for a radiomanifest + */ + get (baseURL, options = { shows: false, streaming: false, calendar: false }) { + return new RadioManifest(baseURL, options ) + } +} + +class RadioManifest { + constructor (baseURL, options) { + this.baseURL = baseURL + this.options = options + + const radiomanifest = fetch(`${baseURL}/radiomanifest.xml`) + return radiomanifest + } + + getShowByName (showName) { + + } + + getStreaming () { + + } + + getSchedule () { + + } + + getShowAtTime () { + + } +} + + function getStreaminfoUrl(siteurl) { - return siteurl + '/streaminfo.json'; // XXX: improve this logic + return siteurl + '/streaminfo.json'; // XXX: improve this logic } function getManifestUrl(siteurl) { - return siteurl + '/radiomanifest.xml'; // XXX: improve this logic + return siteurl + '/radiomanifest.xml'; // XXX: improve this logic } function parseRadioManifest(xml) { - var res = xml.evaluate('/radio-manifest/streaming/source', xml) - var sources = [] - while(true) { - var src = res.iterateNext() - if(src === null) break; - if(!src.hasAttribute("priority")) { - src.setAttribute("priority", "0") - } else if(parseInt(src.getAttribute("priority"), 10) < 0) { - continue; - } - sources.push(src) + var res = xml.evaluate('/radio-manifest/streaming/source', xml) + var sources = [] + while(true) { + var src = res.iterateNext() + if(src === null) break; + if(!src.hasAttribute("priority")) { + src.setAttribute("priority", "0") + } else if(parseInt(src.getAttribute("priority"), 10) < 0) { + continue; } - sources.sort(function cmp(a,b) { - return parseInt(a.getAttribute("priority", 10)) < parseInt(b.getAttribute("priority", 10)); - }) - - res = xml.evaluate('/radio-manifest/schedule', xml) - var scheduleEl = res.iterateNext() - var schedule = null - if(scheduleEl !== null) { - schedule = scheduleEl.getAttribute("url") - } - - res = xml.evaluate('/radio-manifest/shows', xml) - var showsEl = res.iterateNext() - var shows = null - if(showsEl !== null) { - shows = showsEl.getAttribute("src") - } - - var manifest = new Radio(sources, schedule, shows) - return manifest + sources.push(src) + } + sources.sort(function cmp(a,b) { + return parseInt(a.getAttribute("priority", 10)) < parseInt(b.getAttribute("priority", 10)); + }) + + res = xml.evaluate('/radio-manifest/schedule', xml) + var scheduleEl = res.iterateNext() + var schedule = null + if(scheduleEl !== null) { + schedule = scheduleEl.getAttribute("url") + } + + res = xml.evaluate('/radio-manifest/shows', xml) + var showsEl = res.iterateNext() + var shows = null + if(showsEl !== null) { + shows = showsEl.getAttribute("src") + } + + var manifest = new Radio(sources, schedule, shows) + return manifest } function Radio(sources, schedule, shows) { - this.streaming = new RadioStreaming(sources) - this.schedule = schedule - this.shows = shows - this.name = "" + this.streaming = new RadioStreaming(sources) + this.schedule = schedule + this.shows = shows + this.name = "" } Radio.prototype.getStreaming = function() { - return this.streaming + return this.streaming } Radio.prototype.setName = function(name) { - this.name = name + this.name = name } function RadioStreaming(sources) { - this.sources = sources + this.sources = sources } RadioStreaming.prototype.getOptions = function() { - return this.sources.map(function(x) { - return x.getAttribute('name') - }) + return this.sources.map(function(x) { + return x.getAttribute('name') + }) } RadioStreaming.prototype.getSource = function (name) { - if(name === undefined) { - - } - var s = this.sources.find(function(x) { - return x.getAttribute('name') === name - }) - if(s === undefined) return s - return s.getAttribute('src') + if(name === undefined) { + + } + var s = this.sources.find(function(x) { + return x.getAttribute('name') === name + }) + if(s === undefined) return s + return s.getAttribute('src') } async function get(siteurl, options) { - let resp = await fetch(getManifestUrl(siteurl)); - let text = await resp.text() - - var parser = new DOMParser(); - var dom = parser.parseFromString(text, 'text/xml') - var manifest = parseRadioManifest(dom) - - resp = null - try { - resp = await fetch(getStreaminfoUrl(siteurl)); - text = await resp.text() - - var data = JSON.parse(text) - var name = data["icy-name"] - if(name !== undefined) { - manifest.setName(name) - } - } catch (e) { - if(e instanceof TypeError && e.message.startsWith('NetworkError')) { - // the fetch has failed - true - } else if(e instanceof SyntaxError && e.message.startsWith('JSON.parse')) { - true - } - else { - console.error('Error', e) - throw e - } + let resp = await fetch(getManifestUrl(siteurl)); + let text = await resp.text() + + var parser = new DOMParser(); + var dom = parser.parseFromString(text, 'text/xml') + var manifest = parseRadioManifest(dom) + + resp = null + try { + resp = await fetch(getStreaminfoUrl(siteurl)); + text = await resp.text() + + var data = JSON.parse(text) + var name = data["icy-name"] + if(name !== undefined) { + manifest.setName(name) } - - // XXX: in base alle options fai fetch anche di altra roba - return manifest + } catch (e) { + if(e instanceof TypeError && e.message.startsWith('NetworkError')) { + // the fetch has failed + true + } else if(e instanceof SyntaxError && e.message.startsWith('JSON.parse')) { + true + } + else { + console.error('Error', e) + throw e + } + } + + // XXX: in base alle options fai fetch anche di altra roba + return manifest } function parseM3U(body) { - body.split("\n").filter((e) => { - if(e.startsWith("#")) { - return false - } else { - try { new URL(e); return true } - catch {return false} - } - }) + body.split("\n").filter((e) => { + if(e.startsWith("#")) { + return false + } else { + try { new URL(e); return true } + catch {return false} + } + }) } diff --git a/test/radiomanifest.test.js b/test/radiomanifest.test.js new file mode 100644 index 0000000..a42eaf9 --- /dev/null +++ b/test/radiomanifest.test.js @@ -0,0 +1,31 @@ +const radiomanifest = require('../radiomanifest.js') +const chai = require('chai') +chai.use(require('chai-as-promised')) + +const expect = chai.expect + +describe('radiomanifest.js', () => { + + describe('Get a radiomanifest', () => { + + it('should return a Promise', () => { + const p = radiomanifest.get('http://omstring') + expect(p instanceof Promise).to.be.eql(true) + }) + + it('should reject on invalid URL', () => { + const p = radiomanifest.get('http://invalidurl') + expect(p).to.eventually.be.rejected + }) + + }) + + describe('streaming', () => { + it('shoud return a valid streaming URL', () => { + + }) + }) + + + +})